javascript 为什么我的数组/集合/列表在用'map()`迭代时不呈现?[duplicate]

kq0g1dla  于 2023-01-29  发布在  Java
关注(0)|答案(1)|浏览(114)
    • 此问题在此处已有答案**:

Why doesn't my arrow function return a value?(1个答案)
昨天关门了。

  • 我经常遇到下面的问题,但从来没有真正找到一个好的复制目标。大多数时候是由于大量不相关的开销代码。有了这个问题,我试图制作一个简单的例子,可以很容易地用作复制目标。*

我有一系列待办事项:

[
  { id: 1, task: "go to the grocery store", isDone: false },
  { id: 2, task: "walk the dog",            isDone: true  },
  { id: 3, task: "buy a present for John",  isDone: false },
]
    • 这个数组来自何处并不重要。**

它可以是硬编码的:

const todos = [
  { id: 1, task: "go to the grocery store", isDone: false },
  { id: 2, task: "walk the dog",            isDone: true  },
  { id: 3, task: "buy a present for John",  isDone: false },
];

它可能来自服务器上加载的静态文件。

import todos from "../data/todos.json";

这可能是Web API调用的结果。

useEffect(() => {
  fetch("https://api.example.com/v1.0/me/todo-items")
    .then(response => response.json())
    .then(todos => setTodos(todos))
}, []);

它可以由最终用户构建为应用程序逻辑的一部分。

function handleAddTodoSubmit(e) {
  e.preventDefault();
  const todo = { id: nextID, task, isDone };
  setTodos(todos => [...todos, todo]);
  setNextID(nextID => nextID + 1);
  setAddTodoDialogOpen(false);
}

无论如何定义todos,以下内容都不会呈现待办事项:

function TodoList({ todos }) {
  return (
    <ul>
      {todos.map((todo) => {
        <li key={todo.id}>
          <pre>
            <ASCIICheckbox isChecked={todo.isDone} />
            {" "}
            {todo.task}
          </pre>
        </li>
      })}
    </ul>
  );
}

当我检查生成的结构时,我可以看到<ul>元素存在,但是它不包含任何<li>元素。

const TODOS = [
  { id: 1, task: "go to the grocery store", isDone: false },
  { id: 2, task: "walk the dog",            isDone: true  },
  { id: 3, task: "buy a present for John",  isDone: false },
];

function ASCIICheckbox({ isChecked }) {
  const check = isChecked ? "x" : " ";

  return (
    <React.Fragment>[{check}]</React.Fragment>
  );
}

function TodoList({ todos }) {
  return (
    <ul>
      {todos.map((todo) => {
        <li key={todo.id}>
          <pre>
            <ASCIICheckbox isChecked={todo.isDone} />
            {" "}
            {todo.task}
          </pre>
        </li>
      })}
    </ul>
  );
}

function App() {
  return (
    <div>
      <h1>My todo list:</h1>
      <TodoList todos={TODOS} />
    </div>
  );
}

ReactDOM.createRoot(document.querySelector("#root"))
  .render(<React.StrictMode><App /></React.StrictMode>);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="root"></div>

我期望这3个任务被渲染,但是它们没有。
如何修复渲染并显示集合中的项?

8yparm6h

8yparm6h1#

to-do项目未呈现的原因是map()回调没有返回值。
我们先来看看MDN的arrow函数文档:

函数体

Arrow函数可以有一个 * concise body * 或通常的 * block body *。
在简洁体中,只指定一个表达式,该表达式将成为隐式返回值。在块体中,必须使用显式return语句。

const func = (x) => x * x;
// concise body syntax, implied "return"

const func2 = (x, y) => {
  return x + y;
};
// with block body, explicit "return" needed

...

(todo) => {
  <li key={todo.id}>
    <pre>
      <ASCIICheckbox isChecked={todo.isDone} />
      {" "}
      {todo.task}
    </pre>
  </li>
}

使用块体,但没有return语句,因此返回值为undefined
我们可以用多种方法解决这个问题,第一种方法是简单地将return语句添加到回调中。

(todo) => {
  return ( // <- notice the return
    <li key={todo.id}>
      <pre>
        <ASCIICheckbox isChecked={todo.isDone} />
        {" "}
        {todo.task}
      </pre>
    </li>
  );
}

一个三个三个一个
第二种解决方案是将 * block body * 更改为 * concise body *,这可以通过删除{/}块分隔符来实现。

(todo) => ( // <- notice the change from `{` into `(`
  <li key={todo.id}>
    <pre>
      <ASCIICheckbox isChecked={todo.isDone} />
      {" "}
      {todo.task}
    </pre>
  </li>
)
const TODOS = [
  { id: 1, task: "go to the grocery store", isDone: false },
  { id: 2, task: "walk the dog",            isDone: true  },
  { id: 3, task: "buy a present for John",  isDone: false },
];

function ASCIICheckbox({ isChecked }) {
  const check = isChecked ? "x" : " ";

  return (
    <React.Fragment>[{check}]</React.Fragment>
  );
}

function TodoList({ todos }) {
  return (
    <ul>
      {todos.map((todo) => ( // <- notice the change from `{` into `(`
        <li key={todo.id}>
          <pre>
            <ASCIICheckbox isChecked={todo.isDone} />
            {" "}
            {todo.task}
          </pre>
        </li>
      ))}
    </ul>
  );
}

function App() {
  return (
    <div>
      <h1>My todo list:</h1>
      <TodoList todos={TODOS} />
    </div>
  );
}

ReactDOM.createRoot(document.querySelector("#root"))
  .render(<React.StrictMode><App /></React.StrictMode>);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="root"></div>

如果你对第二个解决方案有困难,让我先解释一下grouping operator(/)。在React(特别是JSX)中,常见的是普通的括号和箭头函数的组合。但是,可以使用基本的JavaScript解释这个特性。
使用它们的主要原因是这样你就可以把你的arrow函数用简洁的主体分割成一个多行语句。

const doubles = nrs.map((nr) => nr * 2);

// could also be written as (notice the additional parentheses)
const doubles = nrs.map((nr) => (nr * 2));

// which can be split across lines
const doubles = nrs.map((nr) => (
  nr * 2 // <- now imagine this being a complex statement
));

任何表达式都可以放在括号中,它不必与箭头函数组合。const name = "John Doe"可以写成const name = ("John Doe"),并产生相同的结果。
在上面的例子中,将nr * 2放在单独的一行中是违反直觉的,因为它是一个很小的表达式,但是JSX(它是一个很大的表达式)的可读性从多行中受益匪浅。

<ul>
  {nrs.map((nr) => <li>complex and long structure {nr * 2}</li>)}
</ul>

// could also be written as (notice the additional parentheses)
<ul>
  {nrs.map((nr) => (<li>complex and long structure {nr * 2}</li>))}
</ul>

// which can be split across lines
<ul>
  {nrs.map((nr) => (
    <li>
      complex and long structure {nr * 2}
    </li>
  ))}
</ul>

相关问题