Javascript 组件更新时始终返回相同的道具和状态

Javascript 组件更新时始终返回相同的道具和状态,javascript,reactjs,react-native,Javascript,Reactjs,React Native,我找到了很多解决这个问题的方法,但都不管用 我有一个根据后端响应动态呈现组件的视图 /** * Module dependencies */ const React = require('react'); const Head = require('react-declarative-head'); const MY_COMPONENTS = { text: require('../components/fields/Description'), initiatives: requ

我找到了很多解决这个问题的方法,但都不管用

我有一个根据后端响应动态呈现组件的视图

/**
 * Module dependencies
 */
const React = require('react');
const Head = require('react-declarative-head');

const MY_COMPONENTS = {
  text: require('../components/fields/Description'),
  initiatives: require('../components/fields/Dropdown'),
  vuln: require('../components/fields/Dropdown'),
  severities: require('../components/fields/Dropdown'),
};

const request = restclient({
  timeout: 5000,
  baseURL: '/api',
});

const { DropdownItem } = Dropdown;

class CreateView extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      modal: false,
      states: props.states,
      error: props.error,
      spinner: true,
      state: props.state,
      prevState: '',
      components: [],
    };
    this.handleChange = this.handleChange.bind(this);
    this.getRequiredFields = this.getRequiredFields.bind(this);
    this.onChangeHandler = this.onChangeHandler.bind(this);
    this.changeState = this.changeState.bind(this);
    this.loadComponents = this.loadComponents.bind(this);
  }

  componentDidMount() {
    this.loadComponents();
  }


  onChangeHandler(event, value) {
    this.setState((prevState) => {
      prevState.prevState = prevState.state;
      prevState.state = value;
      prevState.spinner = true;
      return prevState;
    }, () => {
      this.getRequiredFields();
    });
  }

  getRequiredFields() {
    request.get('/transitions/fields', {
      params: {
        to: this.state.state,
        from: this.state.prevState,
      },
    })
      .then((response) => {
        const pComponents = this.state.components.map(c => Object.assign({}, c));
        pComponents.forEach((c) => {
          c.field.required = 0;
          c.field.show = false;
        });
        response.data.forEach((r) => {
          const ob = pComponents.find(c => c.field.name === r.name);
          if (ob) {
            ob.field.required = r.required;
            ob.field.show = true;
          }
        });
        this.setState({
          components: pComponents,
          fields: response.data,
          spinner: false,
        });
      })
      .catch(err => err);
  }

  loadComponents() {
    this.setState((prevState) => {
      prevState.components = Object.keys(MY_COMPONENTS).map((k) => {
        const field = {
          name: k,
          required: 0,
          show: true,
        };
        return {
          field, component: MY_COMPONENTS[k],
        };
      });
      return prevState;
    });
  }

  handleChange(field, value) {
    this.setState((prevState) => {
      prevState[field] = value;
      return prevState;
    });
  }

  changeState(field, value) {
    this.setState((prevState) => {
      prevState[`${field}`] = value;
      return prevState;
    });
  }

  render() {
    const Components = this.state.components;

    return (
      <Page name="CI" state={this.props} Components={Components}>
        <Script src="vendor.js" />
        <Card className="">
            <div className="">
              <div className="">
                <Spinner
                  show={this.state.spinner}
                />
                {Components.map((component, i) => {
                  const Comp = component.component;
                  return (<Comp
                    key={i}
                    value={this.state[component.field.name]}
                    field={component.field}
                    handleChange={this.handleChange}
                    modal={this.state.modal}
                    changeState={this.changeState}
                  />);
                })
                }
              </div>
            </div>
          </div>
        </Card>

      </Page>
    );
  }
}

module.exports = CreateView;
/**
*模块依赖关系
*/
const React=require('React');
const Head=require('react-declarative-Head');
常量MY_组件={
text:require(“../components/fields/Description”),
方案:需要(“../components/fields/Dropdown”),
vuln:require(“../components/fields/Dropdown”),
严重性:要求(“../components/fields/Dropdown”),
};
const request=restclient({
超时:5000,
baseURL:“/api”,
});
const{DropdownItem}=下拉列表;
类CreateView扩展了React.Component{
建造师(道具){
超级(道具);
此.state={
莫代尔:错,
国家:道具,国家,
错误:props.error,
斯宾纳:没错,
状态:props.state,
prevState:“”,
组成部分:[],
};
this.handleChange=this.handleChange.bind(this);
this.getRequiredFields=this.getRequiredFields.bind(this);
this.onChangeHandler=this.onChangeHandler.bind(this);
this.changeState=this.changeState.bind(this);
this.loadComponents=this.loadComponents.bind(this);
}
componentDidMount(){
这是loadComponents();
}
onChangeHandler(事件、值){
this.setState((prevState)=>{
prevState.prevState=prevState.state;
prevState.state=值;
prevState.spinner=true;
返回状态;
}, () => {
这是.getRequiredFields();
});
}
getRequiredFields(){
request.get(“/transitions/fields”{
参数:{
致:this.state.state,
发件人:this.state.prevState,
},
})
。然后((响应)=>{
constpcomponents=this.state.components.map(c=>Object.assign({},c));
pComponents.forEach((c)=>{
c、 field.required=0;
c、 field.show=false;
});
response.data.forEach((r)=>{
const ob=pComponents.find(c=>c.field.name==r.name);
如果(ob){
ob.field.required=r.required;
ob.field.show=true;
}
});
这是我的国家({
组件:P组件,
字段:response.data,
纺纱工:错,
});
})
.catch(err=>err);
}
loadComponents(){
this.setState((prevState)=>{
prevState.components=Object.keys(我的组件).map((k)=>{
常量字段={
姓名:k,,
必填项:0,
秀:没错,
};
返回{
字段,组件:MY_组件[k],
};
});
返回状态;
});
}
handleChange(字段、值){
this.setState((prevState)=>{
prevState[字段]=值;
返回状态;
});
}
变更状态(字段、值){
this.setState((prevState)=>{
prevState[`${field}`]=值;
返回状态;
});
}
render(){
常量组件=this.state.Components;
返回(
{Components.map((component,i)=>{
const Comp=component.component;
返回();
})
}
);
}
}
module.exports=CreateView;
和下拉组件

const React = require('react');

const request = restclient({
  timeout: 5000,
  baseURL: '/api',
});

const { DropdownItem } = Dropdown;

class DrpDwn extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      field: props.field,
      values: [],
    };
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    console.log('state', this.state.field);
    console.log('prevState', prevState.field);
    console.log('prevProps', prevProps.field);
    console.log('props', this.props.field);
  }

  render() {
    const { show } = this.props.field;
    return (show && (
      <div className="">
        <Dropdown
          className=""
          onChange={(e, v) => this.props.handleChange(this.props.field.name, v)}
          label={this.state.field.name.replace(/^./,
            str => str.toUpperCase())}
          name={this.state.field.name}
          type="form"
          value={this.props.value}
          width={100}
          position
        >
          {this.state.values.map(value => (<DropdownItem
            key={value.id}
            value={value.name}
            primary={value.name.replace(/^./, str => str.toUpperCase())}
          />))
          }
        </Dropdown>
      </div>
    ));
  }

module.exports = DrpDwn;
const React=require('React');
const request=restclient({
超时:5000,
baseURL:“/api”,
});
const{DropdownItem}=下拉列表;
类DrpDwn扩展了React.Component{
建造师(道具){
超级(道具);
此.state={
场:道具场,
值:[],
};
}
componentDidUpdate(prevProps、prevState、快照){
console.log('state',this.state.field);
console.log('prevState',prevState.field);
console.log('prevProps',prevProps.field);
console.log('props',this.props.field);
}
render(){
const{show}=this.props.field;
返回(显示和显示)(
this.props.handleChange(this.props.field.name,v)}
label={this.state.field.name.replace(/^./,
str=>str.toUpperCase())}
name={this.state.field.name}
type=“form”
value={this.props.value}
宽度={100}
位置
>
{this.state.values.map(value=>(str.toUpperCase())}
/>))
}
));
}
module.exports=DrpDwn;
代码实际上是有效的,它可以正确地隐藏或显示组件,但问题是我不能在
componentdiddupdate
内执行任何操作,因为
prevProps
prevState
props
总是相同的

我想问题是我总是在变异同一个对象,但我找不到方法

我要做的是填写下拉项


Ps:“真正”的代码是有效的,我修改它是为了在这里发布它

React状态应该是不可变的。由于您正在改变状态,因此无法判断状态是否已更改。特别是,我认为这是造成您问题的主要原因:

this.setState((prevState) => {
  prevState.components = Object.keys(MY_COMPONENTS).map((k) => {
    const field = {
      name: k,
      required: 0,
      show: true,
    };     return {
      field, component: MY_COMPONENTS[k],
    };
  });
  return prevState;
});
可以修改以前的状态以更改其components属性。而是创建一个新状态:

this.setState(prevState => {
  const components = Object.keys(MY_COMPONENTS).map((k) => {
    const field = {
      name: k,
      required: 0,
      show: true,
    };
    return {
      field, component: MY_COMPONENTS[k],
    };
  });
  return { components }
}
你有一个额外的地方,你是变异状态。我不知道这是否导致了您的特殊问题,但无论如何值得一提:

const pComponents = [].concat(this.state.components);
// const pComponents = [...this.state.components];
pComponents.forEach((c) => {
  c.field.required = 0;
  c.field.show = false;
});
response.data.forEach((r) => {
  const ob = pComponents.find(c => c.field.name === r.name);
  if (ob) {
    ob.field.required = r.required;
    ob.field.show = true;
  }
});
您可以创建state.components的副本,但这只是一个浅副本。该数组是一个新数组,但数组中的对象是旧对象。因此,当您设置ob.field.required时,您正在改变旧状态和新状态

如果要更改对象中的特性,则需要在进行更改的每个级别复制这些对象。扩展语法通常是最简洁的方法:

let pComponents = this.state.components.map(c => {
  return {
    ...c,
    field: {
      ...c.field,
      required: 0,
      show: false
    }
  }
});

response.data.forEach(r => {
  const ob = pComponents.find(c => c.field.name === r.name);
  if (ob) {
    // Here it's ok to mutate, but only because i already did the copying in the code above
    ob.field.required = r.required;
    ob.field.show = true;
  }
})


你提到的第一件事是正确的,我不知道我在做什么,但不是解决方案