![](/img/trans.png)
[英]Why my React component does not rerender when Set state was changed?
[英]React: set State or set Prop without a Rerender
目前,我有一個LoginForm
組件,它有一個“on-success”處理函數handleOnSuccess
。 然后使用由“令牌更新”處理程序函數handleUpdateToken
定義的onTokenUpdate
屬性鏈接到父組件。 問題在於handleUpdateToken
函數中的setState
正在強制進行不需要的重新渲染。
我最終需要的是使用成功獲得的值更新LoginForm
組件屬性token
,而不執行重新渲染。 這甚至可能嗎? 根據React: Update Child Component without Rerendering Parent ,這似乎不是,但是,沒有針對我的情況提出可行的替代方案。 我想知道如果這是不可能的,是否有人有任何建議的替代方案。
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
:// /* 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;
在此先感謝您的任何/所有幫助!
如果要更新 child 的props
,則無法阻止渲染parent
。 但是有一種方法可以實現它。
token
存儲在LoginForm
狀態中。componentWillReceiveProps
LoginForm
的state
this.props.onTokenUpdate(token,function);
傳遞一個token
和function
this.props.onTokenUpdate(token,function);
.這個函數將有一個參數,它是來自父代的令牌。 在function
內部,您將更改state
。(如果您想更改父組件中的令牌並發送更新的令牌,則需要這樣做)。render()
,則 parent 中的token
不應處於該state
。 它應該是組件屬性this.state.token
而不是this.props.token
下面是一個通用示例。 代碼筆
這就是我最終要做的(但我接受了@MaheerAli 的回答,因為有些人可能一直在尋找它):
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
:// /* 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;
最值得注意的是,我剛剛定義了一個chooseRender
函數,該函數選擇是否在 Child 中渲染 Plaid。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.