简体   繁体   English

React:设置状态或设置 Prop 而不重新渲染

[英]React: set State or set Prop without a Rerender

Problem:问题:

Currently, I have a LoginForm component that has an "on-success" handler function handleOnSuccess .目前,我有一个LoginForm组件,它有一个“on-success”处理函数handleOnSuccess This the then linked to the parent component with an onTokenUpdate property defined by a "token-update" handler function handleUpdateToken .然后使用由“令牌更新”处理程序函数handleUpdateToken定义的onTokenUpdate属性链接到父组件。 The problem is that the setState in the handleUpdateToken function is forcing an undesired rerender.问题在于handleUpdateToken函数中的setState正在强制进行不需要的重新渲染。

Desired Outcome:期望的结果:

What I ultimately need is to update the LoginForm component property token with the value obtained on success WITHOUT performing a rerender.我最终需要的是使用成功获得的值更新LoginForm组件属性token ,而不执行重新渲染。 Is this even possible?这甚至可能吗? According to React: Update Child Component Without Rerendering Parent it would seem it is not, however, no feasible alternative for my case was suggested.根据React: Update Child Component without Rerendering Parent ,这似乎不是,但是,没有针对我的情况提出可行的替代方案。 Im wondering if anyone had any suggested alternatives if this is not possible.我想知道如果这是不可能的,是否有人有任何建议的替代方案。

Code代码

LoginForm.react.js : LoginForm.react.js :

import React, { Component } from 'react';
import Script from 'react-load-script';
import PropTypes from 'prop-types';


class LoginForm extends Component {
    constructor(props) {
        super(props);

        this.state = {
            linkLoaded: false,
            initializeURL: 'https://cdn.plaid.com/link/v2/stable/link-initialize.js',
        };

        this.onScriptError = this.onScriptError.bind(this);
        this.onScriptLoaded = this.onScriptLoaded.bind(this);

        this.handleLinkOnLoad = this.handleLinkOnLoad.bind(this);

        this.handleOnExit = this.handleOnExit.bind(this);
        this.handleOnEvent = this.handleOnEvent.bind(this);
        this.handleOnSuccess = this.handleOnSuccess.bind(this);

        this.renderWindow = this.renderWindow.bind(this);
    }

    onScriptError() {
        console.error('There was an issue loading the link-initialize.js script');
    }

    onScriptLoaded() {
        window.linkHandler = window.Plaid.create({
            apiVersion: this.props.apiVersion,
            clientName: this.props.clientName,
            env: this.props.env,
            key: this.props.publicKey,
            onExit: this.handleOnExit,
            onLoad: this.handleLinkOnLoad,
            onEvent: this.handleOnEvent,
            onSuccess: this.handleOnSuccess,
            product: this.props.product,
            selectAccount: this.props.selectAccount,
            token: this.props.token,
            webhook: this.props.webhook,
        });

        console.log("Script loaded");
    }

    handleLinkOnLoad() {
        console.log("loaded");
        this.setState({ linkLoaded: true });
    }
    handleOnSuccess(token, metadata) {
        console.log(token);
        console.log(metadata);
        this.props.onTokenUpdate(token);
    }
    handleOnExit(error, metadata) {
        console.log('link: user exited');
        console.log(error, metadata);
    }
    handleOnLoad() {
        console.log('link: loaded');
    }
    handleOnEvent(eventname, metadata) {
        console.log('link: user event', eventname, metadata);
    }

    renderWindow() {
        const institution = this.props.institution || null;
        if (window.linkHandler) {
            window.linkHandler.open(institution);
        }
    }

    static exit(configurationObject) {
        if (window.linkHandler) {
            window.linkHandler.exit(configurationObject);
        }
    }

    render() {
        return (
            <div id={this.props.id}>
                {this.renderWindow()}
                <Script
                    url={this.state.initializeURL}
                    onError={this.onScriptError}
                    onLoad={this.onScriptLoaded}
                />
            </div>
        );
    }
}

LoginForm.defaultProps = {
    apiVersion: 'v2',
    env: 'sandbox',
    institution: null,
    selectAccount: false,
    style: {
        padding: '6px 4px',
        outline: 'none',
        background: '#FFFFFF',
        border: '2px solid #F1F1F1',
        borderRadius: '4px',
    },
};

LoginForm.propTypes = {
    // id
    id: PropTypes.string,

    // ApiVersion flag to use new version of Plaid API
    apiVersion: PropTypes.string,

    // Displayed once a user has successfully linked their account
    clientName: PropTypes.string.isRequired,

    // The Plaid API environment on which to create user accounts.
    // For development and testing, use tartan. For production, use production
    env: PropTypes.oneOf(['tartan', 'sandbox', 'development', 'production']).isRequired,

    // Open link to a specific institution, for a more custom solution
    institution: PropTypes.string,

    // The public_key associated with your account; available from
    // the Plaid dashboard (https://dashboard.plaid.com)
    publicKey: PropTypes.string.isRequired,

    // The Plaid products you wish to use, an array containing some of connect,
    // auth, identity, income, transactions, assets
    product: PropTypes.arrayOf(
        PropTypes.oneOf([
            // legacy product names
            'connect',
            'info',
            // normal product names
            'auth',
            'identity',
            'income',
            'transactions',
            'assets',
        ])
    ).isRequired,

    // Specify an existing user's public token to launch Link in update mode.
    // This will cause Link to open directly to the authentication step for
    // that user's institution.
    token: PropTypes.string,
    access_token: PropTypes.string,

    // Set to true to launch Link with the 'Select Account' pane enabled.
    // Allows users to select an individual account once they've authenticated
    selectAccount: PropTypes.bool,

    // Specify a webhook to associate with a user.
    webhook: PropTypes.string,

    // A function that is called when a user has successfully onboarded their
    // account. The function should expect two arguments, the public_key and a
    // metadata object
    onSuccess: PropTypes.func,

    // A function that is called when a user has specifically exited Link flow
    onExit: PropTypes.func,

    // A function that is called when the Link module has finished loading.
    // Calls to plaidLinkHandler.open() prior to the onLoad callback will be
    // delayed until the module is fully loaded.
    onLoad: PropTypes.func,

    // A function that is called during a user's flow in Link.
    // See
    onEvent: PropTypes.func,


    onTokenUpdate: PropTypes.func,

    // Button Styles as an Object
    style: PropTypes.object,

    // Button Class names as a String
    className: PropTypes.string,
};

export default LoginForm;

App.js : App.js

// /* eslint no-magic-numbers: 0 */
import React, { Component } from 'react';
import { LoginForm } from '../lib';

class App extends Component {
    constructor(props) {
        super(props);
        this.state = {
            access_token: null
        };
        this.handleUpdateToken = this.handleUpdateToken.bind(this)
    }

    handleUpdateToken(access_token) {
        this.setState({ access_token: access_token });
    }

    render() {
        return (
            <LoginForm
                id="Test"
                clientName="Plaid Client"
                env="sandbox"
                product={['auth', 'transactions']}
                publicKey="7a3daf1db208b7d1fe65850572eeb1"
                className="some-class-name"
                apiVersion="v2"
                onTokenUpdate={this.handleUpdateToken}
                token={this.state.access_token}
            >
            </LoginForm>
        );
    }
}

export default App;

Thanks in advance for any/all help!在此先感谢您的任何/所有帮助!

You cannot prevent rendering of parent if you want to update the props of child.如果要更新 child 的props ,则无法阻止渲染parent But there is a way to achieve it.但是有一种方法可以实现它。

  1. You need to store the token in side your LoginForm state.您需要将token存储在LoginForm状态中。
  2. You need to change change the state of the LoginForm in componentWillReceiveProps您需要更改componentWillReceiveProps LoginFormstate
  3. You need to pass a token and function in this.props.onTokenUpdate(token,function);您需要在this.props.onTokenUpdate(token,function);传递一个tokenfunction this.props.onTokenUpdate(token,function); .This function will have an argument which is token from parent. .这个函数将有一个参数,它是来自父代的令牌。 And inside function you will change the state .(This is needed if you want to alter the token in parent component and send updated one).function内部,您将更改state 。(如果您想更改父组件中的令牌并发送更新的令牌,则需要这样做)。
  4. The token in parent shouldn't be in the state if you want to prevent render() .如果您想阻止render() ,则 parent 中的token不应处于该state It should be compoent property它应该是组件属性
  5. Use this.state.token Instead of this.props.token使用this.state.token而不是this.props.token

Below is a general example.下面是一个通用示例。 Codepen代码笔

This is what I ended up doing (but I accepted @MaheerAli answer since some people may have been looking for that instead):这就是我最终要做的(但我接受了@MaheerAli 的回答,因为有些人可能一直在寻找它):

LoginForm.js : LoginForm.js :

class LoginForm extends Component {
    constructor(props) {
        super(props);

        this.state = {
            linkLoaded: false,
            initializeURL: 'https://cdn.plaid.com/link/v2/stable/link-initialize.js',
        };

        this.onScriptError = this.onScriptError.bind(this);
        this.onScriptLoaded = this.onScriptLoaded.bind(this);

        this.handleLinkOnLoad = this.handleLinkOnLoad.bind(this);

        this.handleOnExit = this.handleOnExit.bind(this);
        this.handleOnEvent = this.handleOnEvent.bind(this);
        this.handleOnSuccess = this.handleOnSuccess.bind(this);

        this.renderWindow = this.renderWindow.bind(this);
    }

    onScriptError() {
        console.error('There was an issue loading the link-initialize.js script');
    }

    onScriptLoaded() {
        window.linkHandler = window.Plaid.create({
            apiVersion: this.props.apiVersion,
            clientName: this.props.clientName,
            env: this.props.env,
            key: this.props.publicKey,
            onExit: this.handleOnExit,
            onLoad: this.handleLinkOnLoad,
            onEvent: this.handleOnEvent,
            onSuccess: this.handleOnSuccess,
            product: this.props.product,
            selectAccount: this.props.selectAccount,
            token: this.props.token,
            webhook: this.props.webhook,
        });
    }

    handleLinkOnLoad() {
        console.log("loaded");
        this.setState({ linkLoaded: true });
    }
    handleOnSuccess(token, metadata) {
        console.log(token);
        console.log(metadata);
        this.props.onTokenUpdate(token);
    }
    handleOnExit(error, metadata) {
        console.log('PlaidLink: user exited');
        console.log(error, metadata);
    }
    handleOnLoad() {
        console.log('PlaidLink: loaded');
    }
    handleOnEvent(eventname, metadata) {
        console.log('PlaidLink: user event', eventname, metadata);
    }

    renderWindow() {
        const institution = this.props.institution || null;
        if (window.linkHandler) {
            window.linkHandler.open(institution);
        }
    }

    chooseRender() {
        if (this.props.access_token === null) {
            this.renderWindow()
        }
    }

    static exit(configurationObject) {
        if (window.linkHandler) {
            window.linkHandler.exit(configurationObject);
        }
    }

    render() {
        return (
            <div id={this.props.id}
                 access_token={this.props.access_token}>
                {this.chooseRender()}
                <Script
                    url={this.state.initializeURL}
                    onError={this.onScriptError}
                    onLoad={this.onScriptLoaded}
                />
            </div>
        );
    }
}

App.js : App.js

// /* eslint no-magic-numbers: 0 */
import React, { Component } from 'react';
import { LoginForm } from '../lib';

class App extends Component {
    constructor(props) {
        super(props);
        this.state = {
            access_token: null
        };
        this.handleUpdateToken = this.handleUpdateToken.bind(this)
    }

    handleUpdateToken(access_token) {
        this.setState({ access_token: access_token });
    }

    render() {
        return (
            <LoginForm
                id="Test"
                access_token={this.state.access_token}

                clientName="Plaid Client"
                env="sandbox"
                product={['auth', 'transactions']}
                publicKey="7a3daf1db208b7d1fe65850572eeb1"
                className="some-class-name"
                apiVersion="v2"
                onTokenUpdate={this.handleUpdateToken}
            >
            </LoginForm>
        );
    }
}

export default App;

Most notably, I just defined a chooseRender function which chose whether or not to render Plaid in the Child.最值得注意的是,我刚刚定义了一个chooseRender函数,该函数选择是否在 Child 中渲染 Plaid。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么当 Set 状态改变时我的 React 组件没有重新渲染? - Why my React component does not rerender when Set state was changed? React 无限重新渲染,useEffect 问题,未触发设置 state - React infinite rerender, useEffect issue, no set state triggered 如何在本机反应中根据 state 值在道具内设置条件? - How to set condition inside prop based on state value in react native? 从 prop 事件处理程序设置时,React state 重置 - React state resets when set from prop event handler 如何在 React Hooks 中修改 prop 并将其设置为初始状态? - How to modify prop and set it to initial state in React Hooks? 当 state 第一次通过 DOM 上的 onClick 事件设置为相同的值时,为什么 React 会重新渲染,而不是 react-native? - Why does React rerender when the state is set to the same value the first time via an onClick event on DOM, but not react-native? 在子组件中设置 prop 的值并将值传回 app.js 的状态,做出反应 - Set value of prop in child component and pass value back to state of app.js, react 如何在没有设置高度道具的情况下使用 react-lazyload 或 react-lazy-load? - How to use react-lazyload or react-lazy-load without set height prop? 在 React Js 中设置状态 - Set state in React Js 在React中设置状态 - set state in React
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM