简体   繁体   English

反应 JS map function

[英]React JS map function

I have the following code and I'm trying to simplify it using a map function, perhaps on the array: const columns = ['Title', 'Author', 'Rating']我有以下代码,我正在尝试使用 map function 来简化它,也许在数组上: const columns = ['Title', 'Author', 'Rating']

export const BookshelfListRow = (props) => {

  return (
    <tr className="table-row" >


      <td>
        <input onChange={(e) => { props.Update(e.target.value) }} placeholder={props.book.Title} />
      </td>

      <td>
        <input onChange={(e) => { props.Update(props.book.Title, e.target.value) }} placeholder={props.book.Author} />
      </td>
      
      <td>
        <input onChange={(e) => { props.Update(props.book.Title, props.book.Author, e.target.value) }} placeholder={props.book.Rating} />
      </td>


    </tr>
)}

Please note this is simplified - in my actual code I have 30 columns (meaning 30 separate inputs instead of 3) hence why I'm looking for a way to simplify it as it is currently really long - so essentially what is happening above is the placeholder is iterating through the array [Title,Author,Rating] , and simultaneously on each new line we are adding an item from the array (in the form of props.book[item] ) to the props.Update function.请注意,这是简化的-在我的实际代码中,我有 30 列(意味着 30 个单独的输入而不是 3 个)因此我正在寻找一种方法来简化它,因为它目前真的很长-所以基本上上面发生的是占位符正在遍历数组[Title,Author,Rating] ,同时在每个新行上,我们将数组中的一个项目(以props.book[item]的形式)添加到 props.Update function。 Any ideas how I could use a map function to carry this out?有什么想法可以使用 map function 来执行此操作吗?

You can use map to simplify it.您可以使用map来简化它。 The tricky bit will be the calling of Update with different number of parameters, but that too can be achieved using another map .棘手的一点是使用不同数量的参数调用Update ,但这也可以使用另一个map来实现。

const columns = ['Title', 'Author', 'Rating'];

export const BookshelfListRow = (props) => {
  return (
    <tr className="table-row">
    {
      columns.map((column, i) => (
        <td>
          <input onChange={ e =>
                   props.Update(...[                                            // the parameters to Update consist of
                     ...columns.slice(0, i).map(column => props.book[column]),  // the column values from the start until the current column, map is used here to get the values for those columns
                     e.target.value                                             // and the input value
                   ])
                 }
                 placeholder={ props.book[column] } />
        </td>
      ))
    }
    </tr>
  )
}

Another approach:另一种方法:

The Update function is a mess. Update function 是一团糟。 It can be a lot simpler if it just takes the column that was changed and the value as there is no need for it to send all those props back to the server if only one was changed, like so (this uses computed property names ):如果它只获取已更改的列和值,则可能会简单得多,因为如果仅更改了一个,则无需将所有这些道具发送回服务器,就像这样(这使用计算的属性名称):

const Update = (column, value) =>                                         // takes the column that was changed and the value
  axios.put('http://localhost:4001/books/update', { [column]: value });   // update only that column

Then the rendering will be much simpler also, like so:然后渲染也会简单得多,如下所示:

const columns = ['Title', 'Author', 'Rating'];

export const BookshelfListRow = (props) => {
  return (
    <tr className="table-row">
    {
      columns.map((column, i) => (
        <td>
          <input onChange={ e => props.Update(column, e.target.value) } placeholder={ props.book[column] } />
        </td>
      ))
    }
    </tr>
  )
}

 const columns = ['Title', 'Author', 'Rating'] const update = (val, column) => { console.log(`${column}: ${val}`) } const BookshelfListRow = () => (<table><tbody><tr className="table-row">{ columns.map((column, i) => { return (<td key={i}><input type="text" onChange = {e => update(e.target.value, column)} placeholder={column} /></td >) }) }</tr></tbody></table> ) ReactDOM.render( <BookshelfListRow />, document.getElementById("root") );
 <div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

If you're using the keys of props.book , you can try something like this:如果你使用props.book的键,你可以尝试这样的事情:

import React from "react";

const BookshelfListRow = props => {
  const args = [];
  return (
    <tr className="table-row">
      {Object.keys(props.book).map((key, idx) => {
        if(idx > 0) {
          args.unshift(key);
        }
        const argsCopy = [...args];
        return (
          <td>
            <input
              onChange={e => {
                props.Update(...argsCopy, e.target.value);
              }}
              placeholder={props.book[key]}
            />
          </td>
        );
      })}
    </tr>
  );
};

export default BookshelfListRow;

Otherwise, you can use an array like the one you suggested ( const columns = ['Title', 'Author', 'Rating'] ) and take each value and add it to a copy with each map loop.否则,您可以使用您建议的数组( const columns = ['Title', 'Author', 'Rating'] )并获取每个值并将其添加到每个 map 循环的副本中。

Mapping is a very powerful tool in React.映射是 React 中一个非常强大的工具。 It is most useful when you are try to DRY out some repeated code.当您尝试干掉一些重复的代码时,它是最有用的。 In your case you are trying to DRY out your td 's by mapping over the array columns .在您的情况下,您正试图通过映射数组columns来干燥您的td

Your columns array will need a little more info to make mapping useful.您的列数组将需要更多信息才能使映射有用。 For instance,例如,

const columns = ['Title', 'Author', 'Rating']

columns.map(column => console.log(column)) // Title, Author, Rating

That's not very helpful for your td because it needs the onChange , and placeholder and both require more information than just the strings 'Title', 'Author', and 'Rating'.这对您的td不是很有帮助,因为它需要onChangeplaceholder ,并且两者都需要更多信息,而不仅仅是字符串“Title”、“Author”和“Rating”。

From what I can tell, your book prop is an object that looks something like this:据我所知,您的book道具是 object,看起来像这样:

book: { 
  Title: 'some string', 
  Author: 'some other string',
  Rating: 'some number maybe'
}

You can map over that by using Object.keys .您可以通过使用 map 超过Object.keys But again, that only helps with the placeholder not the onChange .但同样,这只有助于placeholder而不是onChange

The data that you have and the data you are trying to use for your inputs do not seem to have a common enough pattern to utilize map here.您拥有的数据和您尝试用于输入的数据似乎没有足够常见的模式来在此处使用 map。

Possible Solution可能的解决方案

Modify your update function to not require so many parameters to keep the input field generic as possible that way you can map over your columns.修改您的更新 function 以不需要太多参数来保持输入字段尽可能通用,这样您就可以在列上进行 map。

export const BookshelfListRow = (props) => {
  // if you are using React without hooks, just replace this with
  // normal state
  const [state, setState] = useState({ 
    title: '',
    author: '',
    rating: ''
  })
  const update = (e) => { 
    const input = e.currentTarget.value; 
    const attribute = e.currentTarget.name;

    setState({...state, [attribute]: input})
  }

  const apiRequest = (e) => { 
    e.preventDefault();

    // your state is now your request body
    request(state)
  } 
  const columns = ['Title', 'Author', 'Rating']
  return (
    <tr className="table-row" >
      {columns.map(column => (
        <td key={column}>
          <input name={column.toLowerCase()} onChange={update} placeholder={column} />
        </td>
      ))}
    </tr>
)}

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

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