【问题标题】:Best approach for using same component for editing and adding data. Mixing component state with redux store使用相同组件编辑和添加数据的最佳方法。将组件状态与 redux 存储混合
【发布时间】:2019-05-23 05:20:38
【问题描述】:

我正在使用 Redux 在 React 中构建 Web 应用程序。它是简单的设备管理器。我正在使用相同的组件在数据库中添加和更新设备。我不确定我的方法是否正确。在这里您可以找到我的部分解决方案:

更新模式:

在 componentDidMount 中,我正在检查 deviceId 是否在 url 中传递(编辑模式)。如果是这样,我将调用 redux 操作以从数据库中检索数据。我正在使用连接功能,所以当响应到达时,它将被映射到组件道具。

这是我的 mapStateToProps(可能我应该只映射特定的属性,但在这种情况下并不重要)

const mapStateToProps = state => ({
    ...state
})

和componentDidMount:

componentDidMount() {
    const deviceId = this.props.match.params.deviceId;
        if (deviceId) {
            this.props.getDevice(deviceId);
            this.setState({ editMode: true });
        }
    }

接下来,componentWillReceiveProps 将被触发,我将能够调用 setState 以填充表单中的输入。

componentWillReceiveProps(nextProps) {
    if (nextProps.devices.item) {
        this.setState({
            id: nextProps.devices.item.id,
            name: nextProps.devices.item.name,
            description: nextProps.devices.item.description
        });
    }
}

添加模式:

添加模式更简单——我只是在每次输入更改时调用 setState。

handleChange = name => event => {
    this.setState({
        [name]: event.target.value,
    });
};

这就是我的输入的样子:

<TextField
    onChange={this.handleChange('description')}
    label="Description"
    className={classes.textField}
    value={this.state.description}
/>

我不喜欢这种方法,因为我必须在从后端接收数据后调用 setState()。我也在使用 componentWillReceiveProps,这是不好的做法。

有没有更好的方法?例如,我可以只使用 redux 存储而不是组件状态(但我不需要在 redux 存储中输入数据)。也许我可以使用 React ref 字段并摆脱组件状态?

其他问题 - 我真的应该在每个输入 onChange 上调用 setState 吗?

【问题讨论】:

  • 使用 React Router 并检测路由。如果您在/items/create 上,那么您处于添加模式。如果你在/items/:itemId,那么你就处于编辑模式。
  • 这就是我在componentDidMount中所做的。我能够检测到编辑/添加模式,但我不确定是否必须混合组件状态和 redux 存储
  • 传递一个可选的 prop 给组件:如果它的 id 是undefined,你就处于添加模式,否则处于编辑模式。当然,或者只是将 id 作为道具传递。不要在组件中使用路由参数,否则如果将来您想在专用路由中显示编辑,您的组件将中断
  • @iskrzycki 你能添加你在更新模式下使用的mapStateToProps吗?这样我就可以提供一个不做假设的例子。
  • @nebuler 问题已更新,但我只是在“传播”整个 redux 商店

标签: javascript reactjs redux


【解决方案1】:

为了避免使用componentWillReceiveProps,并且因为你使用的是redux,你可以这样做:

class YourComponent extends React.Component {

    state = {
        // ...
        description: undefined,
    };

    static getDerivedStateFromProps(nextProps, prevState) {
        if (prevState.description === undefined && nextProps.description) {
            return { description: nextProps.description };
        }

        return null;
    }

    componentDidMount() {
        const deviceId = this.props.match.params.deviceId;
        if (deviceId) {
            this.props.getDevice(deviceId);
            this.setState({ editMode: true });
        }
    }

    handleChange = name => event => {
        this.setState({
            [name]: event.target.value,
        });
    };

    // ...

    render() {
        let { description } = this.state;
        description = description || ''; // use this value in your `TextField`.

        // ...

        return (
            <TextField
                onChange={this.handleChange('description')}
                label="Description"
                className={classes.textField}
                value={description}
            />
        );
    }

}

const mapStateToProps = (state) => {
    let props = { ...state };
    const { devices } = state;
    if (devices && devices.item) {
        props = {
            ...props,
            id: devices.item.id,
            name: devices.item.name,
            description: devices.item.description,
        };
    }

    return props;
};

export default connect(
    mapStateToProps,
)(YourComponent);

然后您可以访问idnamedescription 认为this.props 而不是this.state。它之所以有效,是因为每次更新 redux 存储时都会评估 mapStateToProps。此外,您将能够通过this.state 访问description 并保持您的TextField 不变。你可以阅读更多关于getDerivedStateFromPropshere的信息。

关于你的第二个问题,每次输入更改时都调用setState 完全可以;这就是所谓的受控组件,react 团队(也包括我)鼓励使用它。见here

【讨论】:

  • 好吧,它看起来很不错,但它可能无法解决我的问题。我使用componentWillReceiveProps 主要是因为我在那里调用setState()(以填充文本框)。正如您在我的问题中的最后一个代码 sn-p 中看到的那样,this.state.description 用作输入值。这就是我感到困惑的原因 - 文本框正在使用组件状态,但从后端接收到的数据连接到道具而不是组件状态。可能我可以在mapStateToProps() 中拨打setState(),但我不确定是否可以。也许我必须切换到 100% redux 商店...
猜你喜欢
  • 2020-08-06
  • 2018-01-21
  • 1970-01-01
  • 1970-01-01
  • 2022-01-02
  • 2017-04-03
  • 1970-01-01
  • 2021-09-25
  • 2014-12-17
相关资源
最近更新 更多