尽管状态更新成功(通过console.log和redux devtools检查),但我无法重新渲染 View

您可以在https://github.com/attendanceproject/djattendance/tree/attendance-redux/ap/static/react-gulp/app上查看代码

大多数代码位于scripts文件夹中,与我的问题有关的最重要的部分如下。每当尝试在WeekBar组件中按下上一个或下一个按钮时,我都尝试重新渲染,以便在那里的日期相应地更新。

容器代码

class Attendance extends Component {
  render() {
    const { dispatch, trainee, date, events, rolls, slips, selectedEvents } = this.props
    console.log('this.props', this.props)
    return (
      <div>
        <div>
        <Trainee trainee={trainee} />
        <WeekBar
          date={date}
          onPrevClick={date => dispatch(prevWeek(date))}
          onNextClick={date => dispatch(nextWeek(date))}/>
        </div>
        <hr />
      </div>
    )
  }
}

Attendance.propTypes = {
  trainee: PropTypes.shape({
    name: PropTypes.string,
    id: PropTypes.number,
    active: PropTypes.bool
  }).isRequired,
  date: PropTypes.object.isRequired,
  events: PropTypes.array.isRequired,
  rolls: PropTypes.array.isRequired,
  slips: PropTypes.array.isRequired,
  selectedEvents: PropTypes.array
}

function select(state) {
  return {
    trainee: state.trainee,
    date: state.date,
    events: state.events,
    rolls: state.rolls,
    slips: state.slips,
    selectedEvents: state.selectedEvents,
  }
}

export default connect(select)(Attendance)

组件代码
export default class WeekBar extends Component {
  render() {
    console.log("render props", this.props)
    // var startdate = this.props.date.weekday(0).format('M/D/YY');
    // var enddate = this.props.date.weekday(6).format('M/D/YY');
    return (
      <div className="btn-toolbar" role="toolbar">
        <div className="controls btn-group">
          <button className="btn btn-info"><span className="glyphicon glyphicon-calendar"></span></button>
        </div>
        <div className="controls btn-group">
          <button className="btn btn-default clndr-previous-button" onClick={(e) => this.handlePrev(e)}>Prev</button>
          <div className="daterange btn btn-default disabled">
            {this.props.date.weekday(0).format('M/D/YY')} to {this.props.date.weekday(6).format('M/D/YY')}
          </div>
          <button className="btn btn-default clndr-next-button" onClick={(e) => this.handleNext(e)}>Next</button>
        </div>
      </div>
    );
  }

  handlePrev(e) {
    console.log("hello!", e)
    this.props.onPrevClick(this.props.date)
  }

  handleNext(e) {
    this.props.onNextClick(this.props.date)
  }
}

WeekBar.propTypes = {
  onPrevClick: PropTypes.func.isRequired,
  onNextClick: PropTypes.func.isRequired,
  date: PropTypes.object.isRequired,
}

reducer 代码
var date = moment()
function handleWeek(state = date, action) {
  switch (action.type) {
    case PREV_WEEK:
      console.log('PREV_WEEK')
      return Object.assign({}, state, {
        date: action.date.add(-7, 'd')
      })
    case NEXT_WEEK:
      return Object.assign({}, state, {
        date: action.date.add(7, 'd')
      })
    default:
      return state
  }
}

export default handleWeek

最佳答案

我没有仔细看过,但您似乎将Moment.js日期用作模型的一部分。具体来说,onNextClick调度一个 Action :dispatch(nextWeek(date))

Action 创建者只需传递Moment.js日期即可:

export function nextWeek(date) {
    return {type: NEXT_WEEK, date}
}

最后,化简器通过调用add对日期对象进行突变:
return Object.assign({}, state, {
  date: action.date.add(7, 'd') // wrong! it's mutating action.date
})

Moment.js add documentation:



但是,我们在Redux文档中强调,化简器必须是纯色的,并且状态绝不能发生突变,否则React Redux不会看到更改。这就是Redux高效的原因,因为它只重新渲染它知道已更改的内容。

我建议的解决方案是停止使用Moment.js作为状态的一部分。使用常规的JavaScript Date对象,请确保切勿将其更改为,并且只能在组件的render方法内部使用Moment.js。

最后,从当前状态派生的实际数据传递是一种反模式。您的操作当前如下所示:
{type: NEXT_WEEK, date}

但是,这是太多信息! reducer 已经从状态知道了当前日期,因此不需要传递它。

相反,您可以在没有日期的情况下执行操作:
{type: NEXT_WEEK}

并教您的 reducer 在计算新日期时使用当前日期。

假设您更改了代码以将Date对象保持在状态,则可以使用普通的JS Date API(尽管不是很好,因为Date也是可变的):
// create a copy of the date object
let newDate = new Date(state.date.getTime());

// mutating here is fine: we mutate a new object
newDate.setDate(newDate.getDate() + 7);

return Object.assign({}, state, {
  date: newDate
})

另外,您可以使用一个名为date-fns的精彩新库,它包含不变性:
import addDays from 'date-fns/add_days';

// ...

return Object.assign({}, state, {
  date: addDays(state.date, 7) // non mutating! :D
})

如果您注意不要改变状态或 Action ,并在数据更改时始终创建新对象,React Redux将根据这些更改正确更新React组件。

10-01 16:01
查看更多