简体   繁体   English

React - 组件中的折射器状态

[英]React - refractor state in a component

I have this component that populates logo into a grid system.我有这个组件可以将徽标填充到网格系统中。 It's getting 2 props which are grid - takes in logos and limit - number of logos shown.它得到 2 个道具,它们是grid - 接受徽标和limit - 显示的徽标数量。

  type Props = {
    grid: [],
    limit: number,
  };

  type State = {
    grid: any,
    queue: any,
  };

  class LogoGrid extends Component<Props, State> {

    state = {
      grid: Object.keys(this.props.grid).map(name => ({name, key: name})).slice(0, this.props.limit),
      queue: Object.keys(this.props.grid).map(name => ({name, key: name})).slice(this.props.limit, Object.keys(this.props.grid).length),
    };

    componentDidMount() {
      this.interval = setInterval(this.updateQueue, SWAP_INTERVAL);
    }

    componentWillUnmount() {
      clearInterval(this.interval);
    }

    getRandomInt = (min: number, max: number) => Math.floor((Math.random() * (max - min)) + min);

    updateQueue = (): void => {
      const { limit } = this.props;
      const grid = [...this.state.grid];
      const queue = [...this.state.queue];
      const replaceIndex = this.getRandomInt(0, limit);
      const removedItem = grid.splice(replaceIndex, 1, queue.shift());
      queue.push(removedItem[0]);

      this.setState({ grid, queue });
    }


    render() {
      const { grid } = this.state;

      return (
        <div className={css.container}>
          {grid.map((item, i) => (          
            <CSSTransitionGroup
              transitionName={css}
              transitionEnterTimeout={SWAP_INTERVAL - 100}
              transitionLeaveTimeout={SWAP_INTERVAL - 100}
            >
              <Logo key={i} name={item.name} color="white" className={css.logo}/>
            </CSSTransitionGroup>
          ))}
        </div>  
      );
    }
  }

  export default LogoGrid;

In the parent component it would be used as below:在父组件中,它将按如下方式使用:

  <LogoGrid grid={rawLogos} limit={12} />

rawLogos in this case is just js file of logos like below:在这种情况下, rawLogos只是徽标的 js 文件,如下所示:

  const url = (filename) => `${process.env.S3_LOGOS_BASE_URL}/logo-${filename}`;

  export default {
    '26grains': url('26grains.svg'),
    ...
    ...
  };

My question is how can I simplify/refractor the LogoGrid component even further especially the way state is written.我的问题是如何进一步简化/折射 LogoGrid 组件,尤其是state的编写方式。

UPDATE:更新:

I tried doing this way but getting an error: Uncaught TypeError: Cannot read property 'map' of undefined我尝试这样做但出现错误: Uncaught TypeError: Cannot read property 'map' of undefined

  state = {
    grid: this.gridItems,
    queue: this.queueItems,
  };

  gridItems = () => {
    const logoGrid = Object.keys(this.props.grid).map(name => ({name, key: name})).slice(0, this.props.limit);
    this.setState({grid: logoGrid})
  }

  queueItems = () => {
    const queueGrid = Object.keys(this.props.grid).map(name => ({name, key: name})).slice(this.props.limit, Object.keys(this.props.grid).length);
    this.setState({queue: queueGrid})
  }

You can't set the state while initializing it.您不能在初始化时设置状态。

You can see an example here: https://codesandbox.io/s/reverent-hill-vvet2你可以在这里看到一个例子: https ://codesandbox.io/s/reverent-hill-vvet2

Or here:或者在这里:

const items = ["hi", "test", "3"];

class MyClass extends React.Component {
  state = {
    items: []
  };

  componentDidMount() {
    this.setItems();
  }

  setItems() {
    console.log(this.props.items);
    const items = this.props.items.map(i => <p>{i}</p>);
    console.log(items);
    this.setState({
      items
    });
  }

  render() {
    return <div>{this.state.items}</div>;
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<MyClass items={items} />, rootElement);

Solution:解决方案:

Set your state AFTER initializing the state with componentDidMount like in the example.像示例中一样,在使用componentDidMount初始化状态后设置状态。

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM