清除redux状态

时间:2018-01-28 19:10:01

标签: reactjs redux react-redux

我有一个显示所选帖子的组件PostsShow

@connect((state) => ({post: state.posts.post}), {fetchPost})    
class PostsShow extends Component {
  componentDidMount() {
    this.props.fetchPost(this.props.match.params.id);
  }

  render() {
    const { post } = this.props;

    if (!post) {
      return <div></div>;
    }

    return (
      <div>
        <Link to='/'>Back</Link>
        <h3>{post.title}</h3>
        <h6>Categories: {post.categories}</h6>
        <p>{post.content}</p>
      </div>
    );
  }
}

问题是,当用户第一次访问该页面时,fetchPost函数使用与所选帖子相关联的一些数据填充州部分(posts.post),当用户选择其他帖子时,他可以查看旧数据1-2秒(在新请求完成之前)。

动作图:

  1. 点击帖子#1
  2. 点击Back按钮
  3. 点击帖子#2
  4. 1秒您可以看到旧的(#1)帖子,直到请求完成并使用帖子(#2)数据刷新组件。
  5. 我是整个redux概念的新手,所以我很好奇你是如何避免这种行为的呢?

    我的解决方案:

    我假设您可以创建一个switch分支,它将使用posts.post值修改状态(null part)并在componentWillUnmount方法上触发此行为。所以:

    动作:

    export function clearPost() {
      return {
        type: CLEAR_POST,
        payload: null
      }
    }
    

    减速机:

    const INITIAL_STATE = { all: [], post: null };
    
    export default function (state = INITIAL_STATE, action) {
      switch (action.type) {
        // ... Other cases
    
        case CLEAR_POST:
          return { ...state, post: null }
    
        default:
          return state;
      }
    }
    

    组件:

    class PostsShow extends Component {
      componentDidMount() {
        this.props.fetchPost(this.props.match.params.id);
      }
    
      componentWillUnmount() {
        this.props.clearPost();
      }
    
      render() {
        // Old render
      }
    }
    

    这是与redux反应的好方法吗?

2 个答案:

答案 0 :(得分:1)

你的州结构并不理想。试着像这样保留你的帖子:

posts: {
    byID: {
        1: {/*the post* no 1/},
        2: {/*the post* no 2/},
        // ...
    }
    allIDs: [2, 1 /*, ...*/],
}

通过这种方式,您可以为列表视图提供帖子ID的有序列表,并通过以下状态显示单个帖子:this.posts.byID['thePostID']

另请参阅how to normalize state上的redux文档。

这也可以解决您的问题,因为当您从商店获取具有尚不存在的ID的帖子时,它将undefined呈现为空div。加载指示器将是最好的展示。

答案 1 :(得分:0)

这是因为您正在进行异步调用,这需要时间来获取新日期,这就是为什么当获取帖子获取新数据时,您的组件将更新并呈现它。 您可以有两种方法: 1)您可以创建一个异步函数,该函数将调度一个动作,该动作将使用有效负载更新减速器

status :LOADING,

一旦fetch函数返回新数据,再次调度一个动作 将更新reducer更新为

status:SUCCESS

并在您的组件中检查商店中道具收到的状态是否为“加载”#39;或者&#39; SUCCESS&#39;如果SUCCESS然后显示新状态,如果LOADING继续显示某些文本,如组件正在加载:

这是示例

SomeComponent.js

export default class SomeComponent extends Component {
  constructor (props) {
    super(props)
    this.model = {}
     }
  render () {
    const {
      status
    } = this.props
    const loading = status === 'LOADING'

    return (
      <Layout>
        <Row>
               <FormField
                  label='First Name'
                  id='first-name'
                  value={details.firstName}
                  onChange={this.update('firstName’)}
                  disabled={loading}
                  mandatory
                />
        </Row>
      </Layout>
    )
  }
}

actions.js

const fetchDetails = (someId) => {
  return (dispatch) => {
    dispatch(dataFetching())
    return http.get(dispatch, `https//someCall`, null, {
      'Accept': SOME_HEADER
    }).then((data) => {
        dispatch(dataFetched(data))
    }).catch((error) => {
      dispatch(someError(`Unable to retrieve the details ${error}`))
    })
  }
}

const dataFetching = () => ({
  type: constants.DATA_FETCHING
})
const dataFetched = (data) => ({
  type: constants.DATA_FETCHED,
  data
})

Reducer.js

  export default function reducer (state = {}, action = {}) {
      switch (action.type) {

        case constants.DATA_FETCHING:
          return Object.assign({}, state, {
            data: {},
            status: 'LOADING'
          })
        case constants.DATA_FETCHED:
          return Object.assign({}, state, {
            data: action.data,
            status: 'SUCCESS'
          })

        default:
          return state
      }

}

第二种方法  你做过的那个,但为了清楚起见,试着使用第一个。