Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs 连接的组件不';从另一个连接的组件更改存储后重新渲染_Reactjs_Redux_React Redux - Fatal编程技术网

Reactjs 连接的组件不';从另一个连接的组件更改存储后重新渲染

Reactjs 连接的组件不';从另一个连接的组件更改存储后重新渲染,reactjs,redux,react-redux,Reactjs,Redux,React Redux,我遇到了一个与redux相关的问题。 我有两个连接的组件,它们是: 头像位于导航栏中,始终可见 负责更改商店中化身图像的配置文件 如果我是对的,当存储更改时,如果需要,任何连接的组件都将重新渲染 在我的例子中,当action UPDATE_CURRENT_用户更新化身图像时,navbar化身只有在我更改路由或重新加载页面后才会获得新图像 我找到了一个解决方案,但很多人说这是一个黑客, 我在主组件中设置了一个侦听器来存储更改,并执行了forceUpdate() 我不想使用它,因为连接的组件应该在存

我遇到了一个与redux相关的问题。 我有两个连接的组件,它们是:

  • 头像位于导航栏中,始终可见
  • 负责更改商店中化身图像的配置文件
  • 如果我是对的,当存储更改时,如果需要,任何连接的组件都将重新渲染

    在我的例子中,当action UPDATE_CURRENT_用户更新化身图像时,navbar化身只有在我更改路由或重新加载页面后才会获得新图像

    我找到了一个解决方案,但很多人说这是一个黑客, 我在主组件中设置了一个侦听器来存储更改,并执行了
    forceUpdate()

    我不想使用它,因为连接的组件应该在存储更改时重新渲染

    用户操作:

    export const getCurrentUser = () => dispatch => {
      axios.get("user").then(user => {
        dispatch({
          type: GET_CURRENT_USER,
          payload: user.data
        });
      });
    };
    
    export const updateCurrentUser = user => dispatch => {
      dispatch({
        type: UPDATE_CURRENT_USER,
        payload: user
      })
    }
    
    用户减速器

    const initialState = {
        user: {}
    }
    
    export default function (state = initialState, action) {
        switch (action.type) {
            case GET_CURRENT_USER:
                return { ...state, user: action.payload };
            case UPDATE_CURRENT_USER:
                return { ...state, user: action.payload }
            default:
                return state;
        }
    }
    
    轮廓组件

    class Profile extends Component {
      render() {
        const { currentUser, updateCurrentUser } = this.props;
        return (
          <div id="profile-container">
            <ProfileSider
              currentUser={currentUser}
              updateCurrentUser={updateCurrentUser}
            />
            <ProfileContent
              currentUser={currentUser}
              updateCurrentUser={updateCurrentUser}
            />
          </div>
        );
      }
    }
    
    const mapStateToProps = state => ({
      currentUser: state.userReducer.user
    });
    
    export default connect(
      mapStateToProps,
      { updateCurrentUser }
    )(Profile);
    
    类配置文件扩展组件{
    render(){
    const{currentUser,updateCurrentUser}=this.props;
    返回(
    );
    }
    }
    常量mapStateToProps=状态=>({
    当前用户:state.userReducer.user
    });
    导出默认连接(
    MapStateTops,
    {updateCurrentUser}
    )(概况);
    
    配置文件的子配置文件侧栏

    class ProfileSider extends Component {
      state = { uploading: false };
    
      triggerAvatarInput() {
        $("#avatarInput").click();
      }
    
      handleChange = async event => {
        this.setState({ ...this.state, uploading: true });
        const avatarFormData = new FormData();
        avatarFormData.append("file", event.target.files[0]);
        axios
          .post("uploadFile", avatarFormData)
          .then(res => {
            const avatarURIFormData = new FormData();
            avatarURIFormData.append("avatar", res.data.fileDownloadUri);
            axios
              .put("user/update", avatarURIFormData)
              .then(res => {
                const { currentUser } = this.props;
                currentUser.avatar = res.data.avatar;
                this.props.updateCurrentUser(currentUser);
                this.setState({
                  ...this.state,
                  uploading: false,
                  avatar: currentUser.avatar
                });
                message.success("Avatar updated successfully", 3);
              })
              .catch(error => {
                this.setState({ ...this.state, uploading: false });
                message.error("Updating avatar failed!", 3);
              });
          })
          .catch(error => {
            this.setState({ ...this.state, uploading: false });
            message.error("Uploading avatar failed!", 3);
          });
      };
    
      render() {
        const { uploading } = this.state;
        const { currentUser } = this.props;
        return (
          <div id="profile-sider">
            <div id="profile-sider-info">
              <div id="profile-sider-info-avatar">
                <div className="container">
                  <div
                    className="overlay-uploading"
                    className={
                      uploading ? "overlay-uploading" : "overlay-uploading hidden"
                    }
                  >
                    <Icon type="loading" style={{ fontSize: 50, color: "#FFF" }} />
                  </div>
                  <div className="overlay" />
                  <div className="overlay-text" onClick={this.triggerAvatarInput}>
                    <Icon type="camera" style={{ fontSize: 20 }} />
                    <span>Update</span>
                  </div>
    
                  <div
                    className="avatar"
                    style={{
                      backgroundImage: "url(" + currentUser.avatar + ")"
                    }}
                  ></div>
                  <input
                    onChange={this.handleChange}
                    type="file"
                    accept="image/png, image/jpeg, image/jpg"
                    id="avatarInput"
                  />
                </div>
              </div>
    
              <h2 style={{ marginTop: 20, textAlign: "center" }}>
                {currentUser.fullName}
              </h2>
              <h4 style={{ textAlign: "center" }}>{currentUser.email}</h4>
            </div>
            <div id="profile-sider-actions">
              <div className="profile-sider-actions-item">
                <Link to="/profile/courses" style={{ transition: 0 }}>
                  <Button type="primary" id="courses-btn">
                    <Icon type="read" style={{ marginRight: 15 }} />
                    My Courses
                  </Button>
                </Link>
              </div>
              <div className="profile-sider-actions-item">
                <Link to="/profile/update">
                  <Button type="primary" id="update-infos-btn">
                    <Icon type="sync" style={{ marginRight: 15 }} />
                    Update Infos
                  </Button>
                </Link>
              </div>
            </div>
          </div>
        );
      }
    }
    
    export default ProfileSider;
    
    class ProfileSider扩展组件{
    状态={上传:false};
    triggerAvatarInput(){
    $(“#avatarInput”)。单击();
    }
    handleChange=异步事件=>{
    this.setState({…this.state,uploading:true});
    const avatarFormData=新表单数据();
    avatarFormData.append(“文件”,event.target.files[0]);
    axios
    .post(“上传文件”,avatarFormData)
    。然后(res=>{
    const avatarURIFormData=新表单数据();
    append(“avatar”,res.data.fileDownloadUri);
    axios
    .put(“用户/更新”,avatarURIFormData)
    。然后(res=>{
    const{currentUser}=this.props;
    currentUser.avatar=res.data.avatar;
    this.props.updateCurrentUser(currentUser);
    这是我的国家({
    …这个州,
    上传:错,
    化身:currentUser.avatar
    });
    message.success(“化身更新成功”,3);
    })
    .catch(错误=>{
    this.setState({…this.state,上载:false});
    错误(“更新化身失败!”,3);
    });
    })
    .catch(错误=>{
    this.setState({…this.state,上载:false});
    消息。错误(“上传化身失败!”,3);
    });
    };
    render(){
    const{upload}=this.state;
    const{currentUser}=this.props;
    返回(
    更新
    {currentUser.fullName}
    {currentUser.email}
    我的课程
    更新信息
    );
    }
    }
    导出默认分析器;
    
    位于导航栏中的化身组件

    class ProfileAvatar extends Component {
      constructor() {
        super();
    
        this.handleClick = this.handleClick.bind(this);
        this.handleOutsideClick = this.handleOutsideClick.bind(this);
    
        this.state = {
          showProfileDropdown: false
        };
      }
    
      componentDidMount() {
        this.props.getCurrentUser();
      }
    
      handleLogout = async () => {
        try {
          await auth.logout();
          this.props.onLogout();
          notification["success"]({
            message: "You have been successfully logged out!"
          });
        } catch (ex) {}
      };
    
      handleClick() {
        if (!this.state.showProfileDropdown) {
          // attach/remove event handler
          document.addEventListener("click", this.handleOutsideClick, false);
        } else {
          document.removeEventListener("click", this.handleOutsideClick, false);
        }
    
        this.setState(prevState => ({
          showProfileDropdown: !prevState.showProfileDropdown
        }));
      }
    
      handleOutsideClick(e) {
        // ignore clicks on the component itself
        if (this.element && this.element.contains(e.target)) {
          return;
        }
    
        this.handleClick();
      }
    
      render() {
        const { currentUser } = this.props;
        return (
          <div
            className="profile-avatar"
            ref={element => {
              this.element = element;
            }}
          >
            <Avatar
              onClick={this.handleClick}
              size="large"
              style={{ color: "#f56a00", backgroundColor: "#fde3cf" }}
              src={currentUser.avatar}
            >
              {currentUser.fullName ? currentUser.fullName.charAt(0) : null}
            </Avatar>
            {this.state.showProfileDropdown && (
              <div className="profile-dropdown-list">
                <List
                  className="dropdown_list dropdown-shadow "
                  size="small"
                  style={{ width: "150px" }}
                  bordered
                  itemLayout="vertical"
                  dataSource={[
                    <Link to="/profile/update" className="profile-list-item">
                      <List.Item className="list-item">
                        <Icon className="profile-icons" type="user" /> My Profile
                      </List.Item>
                    </Link>,
                    <Link to="/profile/courses" className="profile-list-item">
                      <List.Item className="list-item">
                        <Icon className="profile-icons" type="container" /> My
                        Courses
                      </List.Item>
                    </Link>,
                    <List.Item className="list-item">
                      <Icon className="profile-icons" type="question-circle" /> Ask
                      for Help
                    </List.Item>,
                    <List.Item className="list-item" onClick={this.handleLogout}>
                      <Icon className="profile-icons" type="logout" /> Log out
                    </List.Item>
                  ]}
                  renderItem={item => item}
                />
              </div>
            )}
          </div>
        );
      }
    }
    
    const mapStateToProps = state => ({
      currentUser: state.userReducer.user
    });
    
    export default connect(
      mapStateToProps,
      { getCurrentUser }
    )(ProfileAvatar);
    
    class profiler扩展组件{
    构造函数(){
    超级();
    this.handleClick=this.handleClick.bind(this);
    this.handleOutsideClick=this.handleOutsideClick.bind(this);
    此.state={
    ShowProfile下拉列表:false
    };
    }
    componentDidMount(){
    this.props.getCurrentUser();
    }
    handleLogout=async()=>{
    试一试{
    等待身份验证注销();
    this.props.onLogout();
    通知[“成功”]({
    消息:“您已成功注销!”
    });
    }捕获(ex){}
    };
    handleClick(){
    如果(!this.state.showProfile下拉列表){
    //附加/删除事件处理程序
    document.addEventListener(“单击”,this.handleOutsideClick,false);
    }否则{
    document.removeEventListener(“单击”,this.handleOutsideClick,false);
    }
    this.setState(prevState=>({
    showProfileDropdown:!prevState.showProfileDropdown
    }));
    }
    把手外侧咔嗒声(e){
    //忽略对组件本身的单击
    if(this.element&&this.element.contains(e.target)){
    返回;
    }
    这个。handleClick();
    }
    render(){
    const{currentUser}=this.props;
    返回(
    {
    this.element=元素;
    }}
    >
    
    这里有两个问题:

    • 您正在更改存储区中的现有对象
    • 在分派操作时,您正在将完全相同的用户对象发送回存储区
    具体而言,以下几行是原因:

    const{currentUser}=this.props;
    currentUser.avatar=res.data.avatar;
    this.props.updateCurrentUser(currentUser);
    
    currentUser
    是已在Redux存储中的用户对象。此代码会对该对象进行变异,并将其插入存储中

    这导致连接的组件认为实际上什么都没有改变

    解决此问题的最短方法是创建一个新的用户对象,并插入:

    const{currentUser}=this.props;
    const updateuser={…currentUser,avatar:res.data.avatar};
    this.props.updateCurrentUser(updateUser);
    
    为了避免将来出现这种情况,我强烈建议您使用,它可以检测突变,如果发生突变,将抛出错误

    class ProfileAvatar extends Component {
      constructor() {
        super();
    
        this.handleClick = this.handleClick.bind(this);
        this.handleOutsideClick = this.handleOutsideClick.bind(this);
    
        this.state = {
          showProfileDropdown: false
        };
      }
    
      componentDidMount() {
        this.props.getCurrentUser();
      }
    
      handleLogout = async () => {
        try {
          await auth.logout();
          this.props.onLogout();
          notification["success"]({
            message: "You have been successfully logged out!"
          });
        } catch (ex) {}
      };
    
      handleClick() {
        if (!this.state.showProfileDropdown) {
          // attach/remove event handler
          document.addEventListener("click", this.handleOutsideClick, false);
        } else {
          document.removeEventListener("click", this.handleOutsideClick, false);
        }
    
        this.setState(prevState => ({
          showProfileDropdown: !prevState.showProfileDropdown
        }));
      }
    
      handleOutsideClick(e) {
        // ignore clicks on the component itself
        if (this.element && this.element.contains(e.target)) {
          return;
        }
    
        this.handleClick();
      }
    
      render() {
        const { currentUser } = this.props;
        return (
          <div
            className="profile-avatar"
            ref={element => {
              this.element = element;
            }}
          >
            <Avatar
              onClick={this.handleClick}
              size="large"
              style={{ color: "#f56a00", backgroundColor: "#fde3cf" }}
              src={currentUser.avatar}
            >
              {currentUser.fullName ? currentUser.fullName.charAt(0) : null}
            </Avatar>
            {this.state.showProfileDropdown && (
              <div className="profile-dropdown-list">
                <List
                  className="dropdown_list dropdown-shadow "
                  size="small"
                  style={{ width: "150px" }}
                  bordered
                  itemLayout="vertical"
                  dataSource={[
                    <Link to="/profile/update" className="profile-list-item">
                      <List.Item className="list-item">
                        <Icon className="profile-icons" type="user" /> My Profile
                      </List.Item>
                    </Link>,
                    <Link to="/profile/courses" className="profile-list-item">
                      <List.Item className="list-item">
                        <Icon className="profile-icons" type="container" /> My
                        Courses
                      </List.Item>
                    </Link>,
                    <List.Item className="list-item">
                      <Icon className="profile-icons" type="question-circle" /> Ask
                      for Help
                    </List.Item>,
                    <List.Item className="list-item" onClick={this.handleLogout}>
                      <Icon className="profile-icons" type="logout" /> Log out
                    </List.Item>
                  ]}
                  renderItem={item => item}
                />
              </div>
            )}
          </div>
        );
      }
    }
    
    const mapStateToProps = state => ({
      currentUser: state.userReducer.user
    });
    
    export default connect(
      mapStateToProps,
      { getCurrentUser }
    )(ProfileAvatar);