React - 面试练习

IT技术 javascript reactjs
2021-05-11 09:24:24

我在一次采访中得到了以下带有 2 个组件的 React 练习,但我没有设法编译它......问题如下:

更新 Counter 组件以将 onIncrement 回调作为props,并确保它们独立更新计数器的值。每个回调都应采用单个整数值作为参数,该值是计数器现有值的递增量。

代码中有注释,但我的问题是如何实现“onIncrement”函数。

const { Component } = React;
const { render } = ReactDOM;

// state data for 3 counters
const data = [
  { id: 1, value: 1 },
  { id: 2, value: 2 },
  { id: 3, value: 3 }
];

// Counter Component
class Counter extends Component {
  render() {
    const { value } = this.props;
    return (
      <div className="counter">
        <b>{value}</b>
        <div className="counter-controls">
          <button className="button is-danger is-small">-</button>
          //I call the function passed     
          <button className="button is-success is-small" onClick={()=>{onIncrement(this.props.value)}}>+</button>
        </div>
      </div>
    );
  }
}

class App extends Component {
  constructor(props, context) {
    super(props, context);
  }
  
   onIncrement=(value)=>{
   //I tried several things here but I did not manage to make it work. I guess that I need also the id of the object...
   }

  render() {
    return (
      <div>
       
        {data.map(counter => ( 
          <Counter 
            key={counter.id} 
            value={counter.value} 
             //I pass the callback function to the component
            onIncrement={this.onIncrement} 

            />
        ))}
      </div>
    );
  }
}


render(
  <App/>
, document.querySelector('#root'))

2个回答

基本上,您需要使用id来确定value需要更新的内容。您如何设置它,您将无法知道哪些value需要更新(因为您不知道id点击了哪些),也不会value保存。

注意:下面的示例采用idfromevent.target.idvaluefromevent.target.value然后在handleChange回调中解构这是一种比将值传递给 acallback然后将它和另一个值传递给另一个更常见和优雅的解决方案callback(更多的工作,更多的代码,但相同的功能)。


最佳解决方案https : //codesandbox.io/s/rjmx8vw99p

组件/UpdateQuantity.js

import React, { Component, Fragment } from "react";

export default class App extends Component {
  state = {
    items: [
      { id: "Apples", quantity: 0 },
      { id: "Strawberries", quantity: 0 },
      { id: "Grapes", quantity: 0 },
      { id: "Apricots", quantity: 0 }
    ]
  };

  handleChange = ({ target: { id, value } }) => {
    this.setState(prevState => ({
      items: prevState.items.map(item => {
        const nextVal = item.quantity + ~~value; // ~~ === parseInt(val, 10) -- required because the "value" is turned into a string when placed on a DOM element

        return id === item.id
          ? { id, quantity: nextVal > 0 ? nextVal : 0 }
          : { ...item };
      })
    }));
  };

  render = () => (
    <div className="container">
      <h1>Updating Values Inside Array</h1>
      {this.state.items.map(({ id, quantity }) => (
        <div key={id} className="container">
          <div>
            {id} ({quantity})
          </div>
          <button
            id={id}
            value={1}
            style={{ marginRight: 10 }}
            className="uk-button uk-button-primary"
            onClick={this.handleChange}
          >
            +
          </button>
          <button
            id={id}
            value={-1}
            style={{ marginRight: 10 }}
            className="uk-button uk-button-danger"
            onClick={this.handleChange}
          >
            -
          </button>
        </div>
      ))}
    </div>
  );
}

另一种解决方案https://codesandbox.io/s/yq961275rv(不推荐,因为它需要额外的组件和一个额外的回调-但有没有结合所必需的render方式,也没有一个匿名函数() => {}onClick回调)

组件/UpdateQuantity.js

import React, { Component, Fragment } from "react";
import Button from "./button";

export default class App extends Component {
  state = {
    items: [
      { id: "Apples", quantity: 0 },
      { id: "Strawberries", quantity: 0 },
      { id: "Grapes", quantity: 0 },
      { id: "Apricots", quantity: 0 }
    ]
  };

  handleChange = (id, val) => {
    this.setState(prevState => ({
      items: prevState.items.map(item => {
        const nextVal = item.quantity + val;

        return id === item.id
          ? { id, quantity: nextVal > 0 ? nextVal : 0 }
          : { ...item };
      })
    }));
  };

  render = () => (
    <div className="container">
      <h1>Updating Values Inside Array</h1>
      {this.state.items.map(props => (
        <div key={props.id} className="container">
          <div>
            {props.id} ({props.quantity})
          </div>
          <Button
            {...props}
            className="uk-button uk-button-primary"
            handleChange={this.handleChange}
            value={1}
          >
            +
          </Button>
          <Button
            {...props}
            disabled={props.quantity === 0}
            className="uk-button uk-button-danger"
            handleChange={this.handleChange}
            value={-1}
          >
            -
          </Button>
        </div>
      ))}
    </div>
  );
}

组件/button.js

import React, { PureComponent } from "react";
import PropTypes from "prop-types";

export default class Button extends PureComponent {
  static propTypes = {
    children: PropTypes.string.isRequired,
    className: PropTypes.string,
    disabled: PropTypes.bool,
    id: PropTypes.string.isRequired,
    handleChange: PropTypes.func.isRequired,
    value: PropTypes.number.isRequired
  };

  handleClick = () => {
    this.props.handleChange(this.props.id, this.props.value);
  };

  render = () => (
    <button
      disabled={this.props.disabled || false}
      className={this.props.className}
      onClick={this.handleClick}
      style={{ marginRight: 10 }}
    >
      {this.props.children}
    </button>
  );
}

我知道一个答案已被接受,但它实际上并没有完全满足要求,即

每个回调都应采用单个整数值作为参数,该值是计数器现有值的递增量。

接受的答案将事件对象作为参数,这不是指定的要求。严格满足预期要求的唯一方法是绑定唯一

“...... onIncrement 回调作为props......”

对于每个计数器。这种方法有缺点和性能影响,如本文所述

https://codesandbox.io/s/j2vxj620z9 上的工作示例