#17 React-redux 实现用户列表的显示、增加、删除


  • 0
    管理员

    @胡子大哈 我忘记引入16题的userReducer了,这次这样写了,还是有错哈。。

    const ADD_USER = "ADD_USER"
    const DELETE_USER = "DELETE_USER"
    const UPDATE_USER = "UPDATE_USER"
    
    const usersReducer = (state=[],action) => {
      switch(action.type){
        case ADD_USER:
          return [...state, action.user]
        case DELETE_USER:
          return[...state.slice(0,action.index), ...state.slice(action.index+1)]
        case UPDATE_USER:
          return [...state.map((user, index) => {
            if (index === action.index) {
              return {...user, ...action.user}
            } else {
              return user 
            }
          })]
        default:
          return state
      }
    }
    
    class User extends Component {
      render () {
        const { user, deleteUser, index} = this.props
        return (
          <div>
            <div>Name: {user.userName}</div>
            <div>Age: {user.age}</div>
            <div>Gender: {user.gender}</div>
            <button onClick={()=> {deleteUser(user, index)}}>删除</button>
          </div>
        )
      }
    }
    
    class UsersList extends Component {
      constructor() {
        super();
        this.state = {
          index: 0,
          userName: '',
          age: '',
          gender: ''
        }
      }
      
      render () {
        const { userName, age, gender } = this.state
        const { addUser, deleteUser, users } = this.props
    
        return (
          <div>
            {/* 输入用户信息,点击“新增”按钮可以增加用户 */}
            <div className='add-user'>
              <div>Username: <input type='text' value={userName} onChange={e=>{this.setState({userName: e.target.value})}} /></div>
              <div>Age: <input type='number' value={age} onChange={e=>{this.setState({age: e.target.value})}} /></div>
              <div>Gender:
                <label>Male: <input type='radio' name='gender' value='male' onChange={e=>{this.setState({gender: e.target.value})}} /></label>
                <label>Female: <input type='radio' name='gender' value='female' onChange={e=>{this.setState({gender: e.target.value})}} /></label>
              </div>
              <button onClick={()=>{this.setState({index: this.state.index+1});addUser(this.state)}}>增加</button>
            </div>
            {/* 显示用户列表 */}
            <div className='users-list'>
              {users.map((user, index)=>
                <User user={user} deleteUser={deleteUser} index={index} key={index}/>
              )}
            </div>
          </div>
        )
      }
    }
    
    
    /**
     * 环境中已经注入了 React-redux,你可以直接使用 connect,或者 ReactRedux.connect
     */
    const mapStateToProps = (state) => {
      return {
        users: state   
      }
    }
    
    const mapDispatchToProps = (dispatch) => {
      return {
        addUser: (user) => {
          dispatch({
            type: ADD_USER,
            user
          })
        },
        deleteUser: (user, index) => {
          dispatch({
            type: DELETE_USER,
            index: index,
            user
          })
        }
      }
    }
    
    UsersList = connect(
      mapStateToProps,
      mapDispatchToProps
    )(UsersList)
    

  • 0
    administrators

    @陈小俊

    1. 删除用户的时候不需要传入 user,那个是多余的。
    2. userName 应该是 username
    3. age 要转换成数字,否则从 input 里面获取的时候是字符串
    4. 增加用户的时候不需要传入 index,那个也是不需要的。

  • 3
    管理员

    哈~谢谢大哈哥。
    这道题注意的地方挺多的,不愧是全网通过率最低的题啊,大家都在试错呀!

    最终代码分享下:
    input取值的方式不太好,有没人做下优化

    const ADD_USER = "ADD_USER"
    const DELETE_USER = "DELETE_USER"
    const UPDATE_USER = "UPDATE_USER"
    
    //需要引入16题的usersReducer
    const usersReducer =(state=[],action) => {
      switch(action.type){
        case ADD_USER:
          return [...state, action.user]
        case DELETE_USER:
          return [...state.slice(0,action.index), ...state.slice(action.index+1)]
        case UPDATE_USER:
          return [...state.map((user, index) => {
            if (index === action.index) {
              return {...user, ...action.user}
            } else {
              return user 
            }
          })]
        default:
          return state
      }
    }
    
    class User extends Component {
      render () {
        const { user, deleteUser, index} = this.props
        return (
          <div>
            <div>Name: {user.username}</div>
            <div>Age: {user.age}</div>
            <div>Gender: {user.gender}</div>
            <button onClick={()=> {deleteUser(index)}}>删除</button>
          </div>
        )
      }
    }
    
    class UsersList extends Component {
      constructor() {
        super();
        this.state = {
          username: '',
          age: '',
          gender: ''
        }
      }
      
      render () {
        const { username, age, gender } = this.state
        const { addUser, deleteUser, users } = this.props
        return (
          <div>
            <div className='add-user'>
              <div>Username: <input type='text' value={username} onChange={e=>{this.setState({username: e.target.value})}} /></div>
              <div>Age: <input type='number' value={age} onChange={e=>{this.setState({age: parseInt(e.target.value)})}} /></div>
              <div>Gender:
                <label>Male: <input type='radio' name='gender' value='male' onChange={e=>{this.setState({gender: e.target.value})}} /></label>
                <label>Female: <input type='radio' name='gender' value='female' onChange={e=>{this.setState({gender: e.target.value})}} /></label>
              </div>
              <button onClick={()=>addUser(this.state)}>增加</button>
            </div>
            <div className='users-list'>
              {users.map((user, index)=>
                <User user={user} deleteUser={deleteUser} index={index} key={index}/>
              )}
            </div>
          </div>
        )
      }
    }
    
    //需要注入的props
    const mapStateToProps = (state) => {
      return {
        users: state   
      }
    }
    
    //需要注入的函数
    const mapDispatchToProps = (dispatch) => {
      return {
        addUser: (user) => {
          dispatch({
            type: ADD_USER,
            user
          })
        },
        deleteUser: (index) => {
          dispatch({
            type: DELETE_USER,
            index: index
          })
        }
      }
    }
    
    //通过connect高阶组件,将需要的值或者函数作为props传入
    UsersList = connect(
      mapStateToProps,
      mapDispatchToProps
    )(UsersList)
    

  • 1

    @陈小俊 你可以从radio的上层div使用onChange,可以冒泡获取radio的value,这样就不用调用两次onChange


  • 2

    const usersReducer = (state=[], action) => {
      switch (action.type) {
        case 'ADD_USER': 
          return [...state, action.user];
        case 'DELETE_USER':
          let deState = [...state];
          deState.splice(action.index, 1);
          return [...deState];
        case 'UPDATE_USER':
          let upState = [...state];
          upState[action.index] = {...upState[action.index], ...action.user};
          return [...upState];
        default:
          return state;
          
      }
    }
    
    class User extends Component {
      
      handleDeleteUser () {
        if (this.props.onDeleteUser) {
          this.props.onDeleteUser(this.props.index);
        }
      }
      render () {
        const { user } = this.props;
        return (
          <div>
            <div>Name: {user.username}</div>
            <div>Age: {user.age}</div>
            <div>Gender: {user.gender}</div>
            <button onClick={this.handleDeleteUser.bind(this)}>删除</button>
          </div>
        )
      }
    }
    
    class UsersList extends Component {
      
      constructor() {
        super();
        this.state = {
          username: '',
          age: 0,
          gender: ''
        };
        this.handleInputChange = this.handleInputChange.bind(this);
      }
      
      handleInputChange (e) {
        switch (e.target.type) {
          case 'text':
            this.setState({username: e.target.value});
            break;
          case 'number': 
            this.setState({age: Number(e.target.value)});
            break;
          case 'radio':
            this.setState({gender: e.target.value});
            break;
          default:
            break;
        }
      }
    
    handleAddUser () {
        if (this.props.onAddUser) {
          this.props.onAddUser(this.state);
        }
      }
    
      render () {
        const {users} = this.props;
        return (
          <div>
            {/* 输入用户信息,点击“新增”按钮可以增加用户 */}
            <div className='add-user'>
              <div>Username: <input type='text' onChange={this.handleInputChange} value={this.state.username}/></div>
              <div>Age: <input type='number' onChange={this.handleInputChange} value = {this.state.age}/></div>
              <div>Gender:
                <label>Male: <input type='radio' name='gender' value='male' onChange={this.handleInputChange} /></label>
                <label>Female: <input type='radio' name='gender' value='female' onChange={this.handleInputChange}/></label>
              </div>
              <button onClick={this.handleAddUser.bind(this)}>增加</button>
            </div>
            {/* 显示用户列表 */}
            <div className='users-list'>{users.map((user, index) => <User user={user} key={index} index={index} onDeleteUser={this.props.onDeleteUser}/>)}</div>
          </div>
        )
      }
    }
    
    const mapStateToProps = (state) => {
      return {
        users: state
      }
    }
    const mapDispatchToProps = (dispatch) => {
      return {
        onAddUser: (user) => {
          dispatch({type: 'ADD_USER', user})
        },
        onDeleteUser: (index) => {
          dispatch({type: 'DELETE_USER', index: index});
        }
      }
    }
    UsersList = connect(mapStateToProps, mapDispatchToProps)(UsersList);
     
    

  • 0

    大哈哥,帮我看看为什么会报这样的错嘛,我在我本地也试过了,都没有问题。![alt text](image url0_1496724664285_upload-f4d7f403-b422-4d6b-8769-d383b3763de6 )

    代码是这样的:

    const usersReducer = (state, action) => {
       if(!state) {
           return [];
       }
       switch (action.type) {
           case 'ADD_USER':
               return [...state, action.user];
           case 'DELETE_USER':
               return [...state.slice(0, action.index), ...state.slice(action.index + 1)];
           case 'UPDATE_USER':
               return [...state.map((value,key) => {
                   if(key === action.index){
                       return {...value, ...action.user}
                   }else {
                       return value;
                   }
               })];
           default:
               return state;
       }
    };
    
    const store = createStore(usersReducer);
    
    class User extends Component {
    
       handleDeleteUser (index) {
           if(this.props.deleteUser){
               this.props.deleteUser(index);
           }
       }
    
       render () {
           const { user, index } = this.props;
           return (
               <div>
                   <div>Name: {user.username}</div>
                   <div>Age: {user.age}</div>
                   <div>Gender: {user.gender}</div>
                   <button onClick={this.handleDeleteUser.bind(this, index)}>删除</button>
               </div>
           )
       }
    }
    
    class UsersList extends Component {
       constructor (props) {
           super(props);
           this.state = {
               username: '',
               age: '',
               gender: 'male'
           }
       }
    
       handleAddUser (user) {
    
           if(this.props.addUser) {
               this.props.addUser(user);
           }
       }
    
       render () {
           const {users, deleteUser} = this.props;
           const {username, age, gender} = this.state;
           return (
               <div>
                   {/* 输入用户信息,点击“新增”按钮可以增加用户 */}
                   <div className='add-user'>
                       <div>Username: <input type='text' value={username} onChange={(e) => this.setState({username: e.target.value})} /></div>
                       <div>Age: <input type='number' value={age} onChange={(e) => this.setState({age: parseInt(e.target.value)})} /></div>
                       <div>Gender:
                           <label>Male: <input type='radio' name='gender' value='male' checked={!!(gender === 'male')} onChange={e => this.setState({gender: 'male'})} /></label>
                           <label>Female: <input type='radio' name='gender' value='female' checked={!!( gender === 'female')} onChange={e => this.setState({gender: 'female'})} /></label>
                       </div>
                       <button onClick={this.handleAddUser.bind(this, this.state)}>增加</button>
                   </div>
                   {/* 显示用户列表 */}
                   <div className='users-list'>{
                       users && users.map((value,key) => {
                           return (
                               <User user={value} deleteUser={deleteUser.bind(this)} key={key} index={key}></User>
                           )
                   }) }</div>
               </div>
           )
       }
    }
    
    const mapStateToProps = (state) => {
       return {
           user: state
       }
    };
    
    const mapDispatchToProps = (dispatch) => {
       return {
           addUser : (user) => {
               dispatch({type: 'ADD_USER', user: user})
           },
           deleteUser: (index) => {
               dispatch({type: 'DELETE_USER', index: index})
           },
           // updateUser: (action) => {
           //   dispatch({type: 'UPDATE_USER', index: action.index, user: action.user})
           // }
       }
    };
    
    class UsersContainer extends Component {
       constructor(props){
           super(props);
       }
       render () {
           return (
               <UsersList users={this.props.user} addUser={this.props.addUser.bind(this)} deleteUser={this.props.deleteUser.bind(this)} />
           )
       }
    }
    
    UsersContainer = connect(mapStateToProps, mapDispatchToProps)(UsersContainer);
    

  • 0
    administrators

    @niuniu 首先先把代码用 markdown 格式包裹,不然代码没法看格式了。

    你的代码的问题在于题目要求的是 UserListUser,而你的 connect 的结果是 UsersContainer 这是不符合题意的。


  • 0

    @胡子大哈
    噢噢。我明白了。但是这样写也是可以达到效果的是吧。


  • 0
    administrators

    @niuniu 我不能确定你的代码是否符合要求,只有通过了测试的才能算是完全符合要求。因为有些 bug 用肉眼和手动测试测不出来的。


  • 0

    @胡子大哈
    我在本地测试过了,没有问题,可以添加,删除和显示用户列表的。


  • 0
    administrators

    @niuniu 觉得没有 bug 和真的没有 bug 是不一样的,你看到的不一定是对的(或者在某些情况下可能会不对)。

    所以会有 TDD 和 BDD 来帮助我们覆盖不同的需求和逻辑分支保证真的没有 bug。


  • 0

    @胡子大哈
    噢噢,你说的有道理,那我再看看。谢谢大哈哥


  • 1

    @胡子大哈
    通过测试了,哈哈哈。


  • 0

    这是我只是主要 写了下 connect action的思路,仅此而已.并没有给按钮绑定增删方法。仅供参考,有错误还望支持。

    /**
     * 环境中已经注入了 React-redux,你可以直接使用 connect,或者 ReactRedux.connect
     */
    
    const userReducer = (state={},action)=>{
      switch(action.type){
        case "ADD_ITEM":
          return {...state, userList:[...state.userList,action.item]};
        case "SUBSTRACT_ITEM":
          delete state.userList[action.index];
          return {...state, userList:[...state.userList]};
        default:
          return state;
      }
    }
    
    const store = createStore(userReducer,{});
    
    const Add_item_action = (itemObj)=>return {type:"ADD_ITEM",item:itemObj};
    const Substract_item_action = (index)=>return {type:"SUBSTRACT_ITEM",index:index};
    
    
    class User extends Component {
      render () {
        const { user } = this.props
        return (
          <div>
            <div>Name: {user.username}</div>
            <div>Age: {user.age}</div>
            <div>Gender: {user.gender}</div>
            <button>删除</button>
          </div>
        )
      }
    }
    
    
    const mapPropsToState = (state)=>{
      return {userList:state.userList};
    }
    const mapPropsToDispatch = (dispatch)=>{
      return {
        addHandle:(item)=>dispacth(Add_item_action(item)),
        substructHandle:(index)=>dispatch(Substract_item_action(index))
      }
    }
    
    
    const UserListComponent = connect(mapPropsState,mapPropsToDispatch)(UserList);
    
    class UsersList extends Component {
      render () {
        return (
          <div>
            {/* 输入用户信息,点击“新增”按钮可以增加用户 */}
            <div className='add-user'>
              <div>Username: <input type='text' /></div>
              <div>Age: <input type='number' /></div>
              <div>Gender:
                <label>Male: <input type='radio' name='gender' value='male' /></label>
                <label>Female: <input type='radio' name='gender' value='female' /></label>
              </div>
              <button>增加</button>
            </div>
            {/* 显示用户列表 */}
            <div className='users-list'>
              {
                const that = this;
                return (
                    this.props.userList.mpa((item)=>{
                       return(
                         <User username={item.username} age={item.age} gender={item.gender} />
                       )
                     })
                 )
              }
            </div>
          </div>
        )
      }
    }
    

  • 0

    @ScriptOJ 胡子哥,请教一下!这个题目的输入框没必要搞成受控组件吧?我觉得直接通过 ref 得到组件DOM,然后取值,重置值也挺方便的。而搞成受控组件还需要绑定 onchange 事件,同时也需要重置 state,并没有优雅多少。是不是这个例子太简单所以看不出差别?


  • 0

    /**
     * 环境中已经注入了 React-redux,你可以直接使用 connect,或者 ReactRedux.connect
     */
    
    const usersReducer = (state = [], action) => {
      switch (action.type) {
        case 'ADD_USER': 
          return [...state, action.user];
        case 'DELETE_USER':
          return [...state.slice(0, action.index), ...state.slice(action.index+1)];
        case 'UPDATE_USER':
          return [...state.slice(0, action.index), {...state[action.index], ...action.user}, ...state.slice(action.index+1)]
        default:
          return state;
      }
    }
    
    class User extends Component {
      render () {
        const { user, deleteUser, index } = this.props
        return (
          <div>
            <div>Name: {user.username}</div>
            <div>Age: {user.age}</div>
            <div>Gender: {user.gender}</div>
            <button onClick={()=> {deleteUser(user, index)}}>删除</button>
          </div>
        )
      }
    }
    
    class UsersList extends Component {
      state = {
        gender: '',
      }
      
      handleSubmit = () => {
        this.props.addUser({
          username: this.usernameRef.value,
          age: Number(this.ageRef.value),
          gender: this.state.gender,
        })
      }
      
      handleRadioClick = (e) => {
        const gender = e.target.value;
        this.setState({gender});
      }
      
      render () {
        const { users, deleteUser } = this.props
        return (
          <div>
            {/* 输入用户信息,点击“新增”按钮可以增加用户 */}
            <div className='add-user'>
              <div>Username: <input type='text' ref={r => this.usernameRef = r} /></div>
              <div>Age: <input type='number' ref={r => this.ageRef = r}/></div>
              <div>Gender:
                <label>Male: <input type='radio' name='gender' value='male' onClick={this.handleRadioClick} /></label>
                <label>Female: <input type='radio' name='gender' value='female' onClick={this.handleRadioClick} /></label>
              </div>
              <button onClick={this.handleSubmit}>增加</button>
            </div>
            {/* 显示用户列表 */}
            <div className='users-list'>
              {users.map((user, index)=>
                <User user={user} deleteUser={deleteUser} index={index} key={index}/>
              )}
            </div>
          </div>
        )
      }
    }
    
    const mapStateToProps = (state) => {
      return {
        users: state   
      }
    }
    
    const mapDispatchToProps = (dispatch) => {
      return {
        addUser: (user) => {
          dispatch({
            type: 'ADD_USER',
            user
          })
        },
        deleteUser: (user, index) => {
          dispatch({
            type: 'DELETE_USER',
            index: index,
            user
          })
        }
      }
    }
    
    UsersList = connect(
      mapStateToProps,
      mapDispatchToProps
    )(UsersList)
    

  • 0

    @ScriptOJ 请教一下 提示:新增用户以后,应该返回新的数组

     * 环境中已经注入了 React-redux,你可以直接使用 connect,或者 ReactRedux.connect
     */
    
    const usersReducer = (state = [],action) => {
      switch(action.type) {
        case 'add':
          return [...state,action.payload]
        case 'delete':
          return [...state.slice(0,action.index),...state.slice(action.index + 1)]
        default:
          return state
      }
    }
    
    class User extends Component {
      render () {
        const { user,deleteOne,index } = this.props
        return (
          <div>
            <div>Name: {user.username}</div>
            <div>Age: {user.age}</div>
            <div>Gender: {user.gender}</div>
            <button onClick={() => this.deleteOne(index)}>删除</button>
          </div>
        )
      }
    }
    
    class UsersList extends Component {
      constructor() {
        this.state = {
          username:'',
          age:'',
          gender:''
        }
      }
      handleUsername(e) {
        this.setState({
          username:e.target.value
        })
      }
      handleAge(e) {
        this.setState({
          age:Number(e.target.value)
        })
      }
      handleGender(e) {
        this.setState({
          gender:e.target.name
        })
      }
      addUser() {
        let {addUser} = this.props
        addUser(this.state)
        this.setState((prvState,nextprops) => {
          return {
            username:'',
            age:'',
            gender:''
          }
        })
      }
      render () {
        let {deleteOne,list} = this.props
        return (
          <div>
            {/* 输入用户信息,点击“新增”按钮可以增加用户 */}
            <div className='add-user'>
              <div>Username: <input type='text' onInput={(e) => this.handleUsername(e)} value={this.state.username} /></div>
              <div>Age: <input type='number' onInput={(e) => this.handleAge(e)} value={this.state.age} /></div>
              <div>Gender:
                <label>Male: <input onClick={(e) => this.handleGender(e)} type='radio' name='gender' value='male' value={this.state.gender} /></label>
                <label>Female: <input onClick={(e) => this.handleGender(e)} type='radio' name='gender' value='female' value={this.state.gender} /></label>
              </div>
              <button onClick={this.addUser.bind(this)}>增加</button>
            </div>
            {/* 显示用户列表 */}
            <div className='users-list'>
            {
              /* TODO */
              list.map((item,key) => <User deleteOne={deleteOne} index={key} username={item.username} age={item.age} gender={item.gender} key={key} />)
            }
            </div>
          </div>
        )
      }
    }
    
    let mapStateToProps = (state) => {
      return {
        list:state
      }
    }
    let mapDispatchToProps = (dispatch,getState) => {
      return {
        addUser:function(user) {
          dispatch({
            type:'add',
            payload:user
          })
        },
        delete:function(index) {
          dispatch({
            type:'delete',
            index:index
          })
        }
      }
    }
    
    connect(mapStateToProps,mapDispatchToProps)(UsersList)
    

  • 0

     * 环境中已经注入了 React-redux,你可以直接使用 connect,或者 ReactRedux.connect
     */
    
      const usersReducer = (state, action)=> {
        if(!state){
            return []
        }
        let newState = [...state]   // 另一种复制数组的方法
        switch(action.type){
            case 'ADD_USER':
                newState.push(action.user)  
                break
            case 'DELETE_USER':
                newState.splice(action.index, 1)
                break
            case 'UPDATE_USER':
                const oldUser = newState[action.index]
                const newUser = action.user
                newState[action.index] = {...oldUser, ...newUser}
                break
            default:
                return state    // 需要原封不动地返回,不然会直接返回一个全新的数组
        }
        return newState
    }
    
    class User extends Component {
    static propTypes = {
      user: PropTypes.object,
      onDeleteUser: PropTypes.func
    }  
    handleDeleteUser(){
      if(this.props.onDeleteUser){
        this.props.onDeleteUser(this.props.idx)
      }
    }
    render () {
      const { user } = this.props
      return (
        <div>
          <div>Name: {user.username}</div>
          <div>Age: {user.age}</div>
          <div>Gender: {user.gender}</div>
          <button onClick={this.handleDeleteUser.bind(this)}>删除</button>
        </div>
      )
    }
    }
    const mapDispatchToProps1 = (dispatch) => {
    return {
      'onDeleteUser':(idx) => {
        dispatch({type:'DELETE_USER', index:idx})
      }
    }
    }
    User = connect(null, mapDispatchToProps1)(User)
    class UsersList extends Component {
    static propTypes = {
      usersList: PropTypes.array,
      onAddUser: PropTypes.func
    }
    constructor(){
      super()
      this.state = {
        // user: { // 这样好清理  // 会出现不可控的警告
        //   userName: '',
        //   age: 0
        // }
        username:'',
        age: '',
        gender: ''
      }
    }
    handleAddUser(){
      if(this.props.onAddUser){
        const user = {
          username: this.state.username,
          age:  parseInt(this.state.age),
          gender: this.state.gender
        }
        this.props.onAddUser(user)
        this.setState({userName:'',age:'',gender:''})  // 清空用户输入
      }
    }
    handleTypeName(event){
      this.setState({
        username:event.target.value
      })  
    }
    handleTypeAge(event){
      this.setState({
        age:event.target.value
      })  
    }
    
    handleGender(event){
      this.setState({
        gender:event.target.value
      })
    }
    render () {
      return (
        <div>
          {/* 输入用户信息,点击“新增”按钮可以增加用户 */}
          <div className='add-user'>
            <div>Username: <input type='text' value={this.state.username} onChange={this.handleTypeName.bind(this)}/></div>
            <div>Age: <input type='number' value={this.state.age} onChange={this.handleTypeAge.bind(this)} /></div>
            <div>Gender:
              <label>Male: <input type='radio' name='gender' value='male'  onClick={this.handleGender.bind(this)} /></label>
              <label>Female: <input type='radio' name='gender' value='female' onClick={this.handleGender.bind(this)} /></label>
            </div>
            <button onClick={this.handleAddUser.bind(this)}>增加</button>
          </div>
          {/* 显示用户列表 */}
          <div className='users-list'>{this.props.usersList.map((user, idx)=>{
            return <User key={idx} idx={idx} user={user} />
          })}</div>
        </div>
      )
    }
    }
    const mapStateToProps = (state) => {
      return {
          usersList: state  // 有提示过usersReducer 的 state 就是一个数组
      }  
    }
    const mapDispatchToProps2 = (dispatch) => {  
      return {
        'onAddUser':(user) => {
          dispatch({type:'ADD_USER', user:user})
        }
      }
    }
    UsersList = connect(mapStateToProps, mapDispatchToProps2)(UsersList)
    

    给个通过的答案给大家参考,请多指教(有一点点不完美,清空输入时单选框没控制好)


  • 0

    未通过,提示不懂。。。。

    /**
     * 环境中已经注入了 React-redux,你可以直接使用 connect,或者 ReactRedux.connect
     */
    
    const userReducer = (state, action) => {
      if (!state) {
        return []
      }
      switch (action.type) {
        case ADD_USER: 
          return [...state, {...action}]
        case DELETE_USER:
          const newState = [...state]
          newState.filter((item) => {
            return item.username !== action.username
          })
          return newState
        default:
          return state
      }
    }
    
    const store = createStore(userReducer)
    
    class User extends Component {
      static propTypes = {
        onDeleteUser: PropTypes.func,
        user: PropTypes.object
      }
      
      handleDeleteUser (username) {
        if (this.props.onDeleteUser) {
          this.props.onDeleteUser(username)
        }
      }
      
      render () {
        const { user } = this.props
        return (
          <div>
            <div>Name: {user.username}</div>
            <div>Age: {user.age}</div>
            <div>Gender: {user.gender}</div>
            <button onClick={this.handleDeleteUser.bind(this, user.username)}>删除</button>
          </div>
        )
      }
    }
    
    const mapDispathProps = dispath => {
      return  {
        onDeleteUser (username) => {
          dispath({
            type: 'DELETE_USER',
            username,
          })
        }
      }
    }
    
    User = connect(null, mapDispathProps)(User)
    
    class UsersList extends Component {
      static propTypes = {
        onAddUser: PropTypes.func,
        userList: PropTypes.array
      }
      
      constructor () {
        super()
        this.state = {
          user: {
            name: '',
            age: '',
            gender: ''
          }
        }
      }
      
      handleAddUser () {
        if (this.props.onAddUser) {
          this.props.onAddUser(this.state.user)
        }
      }
      
      handleName (e) {
        this.setState({
          ...this.state.user,
          name: Number(e.target.value)
        })
      }
      
      handleAge (e) {
        this.setState({
          ...this.state.user,
          age: e.target.value
        })
      }
      
      handleGender (e) {
        this.setState({
          ...this.state.user,
          gender: e.target.value
        })
      }
      
      render () {
        return (
          <div>
            {/* 输入用户信息,点击“新增”按钮可以增加用户 */}
            <div className='add-user'>
              <div>Username: <input type='text' value={this.state.user.name} onChange={this.handleName}/></div>
              <div>Age: <input type='number' value={this.state.user.age} onChange={this.handleAge}/></div>
              <div>Gender:
                <label>Male: <input type='radio' name='gender' value='male' onChange={this.handleGender.bind(this)}/></label>
                <label>Female: <input type='radio' name='gender' value='female' onChange={this.handleGender.bind(this)}/></label>
              </div>
              <button onClick={this.handleAddUser.bind(this)}>增加</button>
            </div>
            {/* 显示用户列表 */}
            <div className='users-list'>{this.props.usersList.map((item, index) => {
              <User {...item} key={index} />
            })}</div>
          </div>
        )
      }
    }
    
    const mapStateProps = state => {
      return {
        usersList: state
      }
    }
    const mapDispathPropsAddUser = dispath => {
      return {
        onAddUser(userObj) {
          dispath({
            type: 'ADD_USER',
            userObj,
          })
        }
      }
    }
    
    UsersList = connect(mapStateProps, mapDispathPropsAddUser)(UsersList)
    
    
    

  • 0

    /**
     * 环境中已经注入了 React-redux,你可以直接使用 connect,或者 ReactRedux.connect
     */
    
    const usersReducer = (state = [], action) => {
      switch (action.type) {
        case 'ADD_USER':
          return [...state, action.user]
        case 'DELETE_USER':
          return [...state.slice(0, action.index), ...state.slice(action.index + 1)]
        case 'UPDATE_USER':
          return [...state.slice(0, action.index), {...state[action.index], ...action.user}, ...state.slice(action.index + 1)]
        default:
          return state
      }
    }
    
    class User extends Component {
      constructor() {
        super()
        this.handleDeleteUser = this.handleDeleteUser.bind(this)
      }
      
      handleDeleteUser() {
        const { index, onDeleteUser } = this.props
        if (onDeleteUser) {
          onDeleteUser(index)
        }
      }
      
      render () {
        const { user } = this.props
        return (
          <div>
            <div>Name: {user.username}</div>
            <div>Age: {user.age}</div>
            <div>Gender: {user.gender}</div>
            <button onClick={this.handleDeleteUser}>删除</button>
          </div>
        )
      }
    }
    
    class UsersList extends Component {
      constructor() {
        super()
        this.state = {
          username: '',
          age: '',
          gender: ''
        }
        
        this.handleUsernameChange = this.handleUsernameChange.bind(this)
        this.handleAgeChange = this.handleAgeChange.bind(this)
        this.handleGenderChange = this.handleGenderChange.bind(this)
        this.handleAddUser = this.handleAddUser.bind(this)
      }
      
      handleUsernameChange(evt) {
        this.setState({
          username: evt.target.value
        })
      }
      
      handleAgeChange(evt) {
        this.setState({
          age: Number(evt.target.value)
        })
      }
      
      handleGenderChange(evt) {
        this.setState({
          gender: evt.target.value
        })
      }
      
      handleAddUser() {
        if (this.props.onAddUser) {
          this.props.onAddUser(this.state)
        }
      }
    
      render () {
        const { username, age } = this.state
        const { users, onDeleteUser } = this.props
        const usersListNode = users.map((user, index) => {
          return <User key={index} index={index} user={user} onDeleteUser={onDeleteUser} />
        })
    
        return (
          <div>
            {/* 输入用户信息,点击“新增”按钮可以增加用户 */}
            <div className='add-user'>
              <div>Username: <input type='text' value={username} onChange={this.handleUsernameChange} /></div>
              <div>Age: <input type='number' value={age} onChange={this.handleAgeChange} /></div>
              <div onChange={this.handleGenderChange}>Gender:
                <label>Male: <input type='radio' name='gender' value='male' /></label>
                <label>Female: <input type='radio' name='gender' value='female' /></label>
              </div>
              <button onClick={this.handleAddUser}>增加</button>
            </div>
            {/* 显示用户列表 */}
            <div className='users-list'>{usersListNode}</div>
          </div>
        )
      }
    }
    
    const mapStateToProps = state => {
      return {
        users: state
      }
    }
    
    const mapDispatchToProps = dispatch => {
      return {
        onAddUser: user => {
          dispatch({
            type: 'ADD_USER',
            user: user
          })
        },
        onDeleteUser: index => {
          dispatch({
            type: 'DELETE_USER',
            index: index
          })
        }
      }
    }
    
    UsersList = connect(mapStateToProps, mapDispatchToProps)(UsersList)
    

登录后回复
 

与 ScriptOJ 的连接断开,我们正在尝试重连,请耐心等待