【问题标题】:How to prevent children component from rerendering?如何防止子组件重新渲染?
【发布时间】:2020-03-09 16:45:17
【问题描述】:

我的搜索栏组件改变了布局组件的状态。因此,Layout 组件会触发其所有子组件的重新渲染。我尝试实现 React.memo(),但对我没有帮助。请纠正我。提前谢谢!

布局组件:

export default class Layout extends Component {
    state = {
        cityName: "",
        date: "",
        icon: "",
    };

    searchbarSubmitHandler = e => {
        const cityName =
            e.target.children[0].firstChild.children[0].value;
        this.setState({
            cityName: cityName
        });
        console.log(this.state.cityName);
        e.preventDefault();
    };

    searchbarChangeHandler = e => {
        this.setState({
            cityName: e.target.value
        });
    };
    render() {
        return (
            <div>
                <Searchbar
                    submit={this.searchbarSubmitHandler}
                    change={this.searchbarChangeHandler}
                />
                <Switch>
                    <Route
                        exact
                        path="/"
                        component={() =>
                            <CurrentWeather icon={this.state.icon} />
                        }
                    />
                    <Route
                        path="/24h-weather"
                        component={HourlyWeather}
                    />
                </Switch>
            </div>
        );
    }
}

搜索栏组件:

const searchbar = props => {
    return (
        <div className="searchbar">
            <form onSubmit={props.submit}>
                <div className="inputs">
                    <div className="inputTextWrapper">
                        <input
                            className="inputText"
                            type="text"
                            placeholder="City name..."
                            onChange={props.change}
                        />
                    </div>

                    <input
                        className="inputSubmit"
                        type="submit"
                        value="Search"
                    />
                </div>
            </form>
        </div>
    );
};

export default searchbar;

我不想重新渲染的 CurrentWeather 组件:

const currentWeather = props => {
    return (
        <div className="container">
            <h3>London, UK</h3>
            <img
              src={`http://openweathermap.org/img/wn/${props.icon}.png`}
              alt="weather icon"
            />
        </div>
    );
};

const areEqual = (prevProps, nextProps) => prevProps === nextProps;

export default React.memo(currentWeather, areEqual);

【问题讨论】:

  • 你能为此做一个codepen吗?我建议将路由器组件中的开关分开,并为功能提供更多信息的名称。

标签: javascript reactjs optimization react-hooks


【解决方案1】:

我建议不要将图标存储在父组件的状态中,而是存储在子组件中,因为这样可以减少依赖关系。如果您需要从父级设置,请查看 udi 上方的答案

【讨论】:

    【解决方案2】:

    问题是

    <Route
        exact
        path="/"
        component={() => <CurrentWeather icon={this.state.icon} />}
        />
    

    component 的工作方式是“路由器使用 React.createElement 从给定组件创建一个新的 React 元素。现有组件被卸载并安装新组件,而不是仅仅更新现有组件”

    https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/Route.md#component

    如果你把这个改成render,你就不会得到这个效果,也不会重新创建这个组件。

    <Route
        exact
        path="/"
        render={() => <CurrentWeather icon={this.state.icon} />}
        />
    

    https://codesandbox.io/s/restless-hill-2ykhq 显示这个工作

    【讨论】:

    • 您的解决方案对我有用!我学到了很多。谢谢!其实没想到这么快的回复?
    • 另外,我从这个“导出默认主页”更改了子组件的导出默认值;到这个“导出默认 React.memo(Home);”
    【解决方案3】:

    问题可能是传递给CurrentWeatherprops 参数是一个对象,因此您的React.memo 第二个参数(areEqual)检查对象是否相等。
    在不同的渲染过程中传递的两个 props 对象不会严格相等,甚至不完全相等,因为它们引用内存中的不同位置 - 因此,prevProps === nextProps 将始终返回 false。

    您可能希望将areEqual 重构为:

    const areEqual = (prevProps, nextProps) => prevProps.icon === nextProps.icon;
    

    假设icon prop 是传递给CurrentWeather 的props 中唯一发生变化或我们关心其变化的prop。

    【讨论】:

    • 这是不正确的,传递给 CurrentWeather 的唯一属性是 icon,它是一个字符串。 React.Memo 将做一个浅层比较,其中将包括icon prop。
    • 唯一传递给 CurrentWeather 的 prop 可能是 icon,但 CurrentWeather 仍然传递了一个 props 对象 - 问题中存在的 areEqual 的实现比较了前一个和下一个 @987654335 @ 对象,而不是专门的 icon 道具。对象的浅比较仍然是一个引用检查,然后每次都会返回false
    • 啊,我知道你来自哪里。他自己创建的平等检查的事实是不正确的。在那种情况下,不调用他自己的平等检查会起作用
    猜你喜欢
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 2021-01-07
    • 2021-12-05
    • 2020-06-17
    • 2021-05-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多