反応リストなし.マップ
34981 ワード
私たちが反応してデータをレンダリングするとき、我々はしばしば配列をつかみ、Aを行います
私が使用するコンポーネントを示します、そして、我々がそれを調べるように、我々は同時にJSX要素を操作する方法を学びます.
問題
この壊れたコードを取ると、リストを変更するときに頭を再現するバグだけでなく、複雑です.
私はこのような多くの醜いコードを見ます.
いずれにしても、私たちの例題を作るためには、まずレンダリングするアイテムを抽出します.これによって、コードが動作しないようになります.
次のように書きます.
解決策
ので、書きましょう
最初に知っていることは、我々が書くとき
記事からのすべてのコードは、ここにあります.
-
追加
コメントで作られたポイントのカップルに答えて、私は私がちょうど最適化すると思いました
.map()
インターフェイスを書くには.JSXマークアップのインストラクションステートメントを含めると、あまり理解できなくなります.私が使用するコンポーネントを示します、そして、我々がそれを調べるように、我々は同時にJSX要素を操作する方法を学びます.
問題
この壊れたコードを取ると、リストを変更するときに頭を再現するバグだけでなく、複雑です.
function App1() {
const [render, setRender] = useState(items)
return (
<Box>
<List className="App">
{/* WRITE THE LIST TO THE UI */}
{render.map((item, index) => {
const [on, setOn] = useState(item.on)
return (
<ListItem key={index + item.name}>
<ListItemText primary={item.name} />
<ListItemSecondaryAction>
<Box display="flex">
<Box>
<Switch
checked={on}
onChange={() => setOn((on) => !on)}
/>
</Box>
<Box ml={1}>
<IconButton
color="secondary"
onClick={() => remove(item)}
>
<MdClear />
</IconButton>
</Box>
</Box>
</ListItemSecondaryAction>
</ListItem>
)
})}
</List>
<Button variant="contained" color="primary" onClick={add}>
Add
</Button>
</Box>
)
function add() {
setRender((items) => [
{ name: "Made up at " + Date.now(), on: false },
...items
])
}
function remove(item) {
setRender((items) => items.filter((i) => i !== item))
}
}
我々はアイテムのリストを持っているし、それらをレンダリングし、それぞれを操作したい.これは、最初の時間をレンダリングしますが、追加または削除アイコンをクリックし、それがクラッシュします.我々はマップ内のコンポーネントを使用していないので、フックを使用することはできません.試してみましょう私はこのような多くの醜いコードを見ます.
いずれにしても、私たちの例題を作るためには、まずレンダリングするアイテムを抽出します.これによって、コードが動作しないようになります.
function RenderItem({ item, remove }) {
const [on, setOn] = useState(item.on)
return (
<ListItem>
<ListItemText primary={item.name} />
<ListItemSecondaryAction>
<Box display="flex">
<Box>
<Switch
checked={on}
onChange={() => setOn((on) => !on)}
/>
</Box>
<Box ml={1}>
<IconButton
color="secondary"
onClick={() => remove(item)}
>
<MdClear />
</IconButton>
</Box>
</Box>
</ListItemSecondaryAction>
</ListItem>
)
}
一度我々はそれを使用するように我々のアプリを更新している:function App2() {
const [render, setRender] = useState(items)
return (
<Box>
<List className="App">
{render.map((item, index) => (
<RenderItem
remove={remove}
key={item.name + index}
item={item}
/>
))}
</List>
<Button variant="contained" color="primary" onClick={add}>
Add
</Button>
</Box>
)
function add() {
setRender((items) => [
{ name: "Made up at " + Date.now(), on: false },
...items
])
}
function remove(item) {
setRender((items) => items.filter((i) => i !== item))
}
}
これは非常に良いですが、それはまだ混乱のビットは、我々の鍵の構造は、我々はアイテムが追加されたり削除されたときに我々は必要がない再レンダリングを作成するつもりです、そして我々はまだ{
とrender.map
など次のように書きます.
function App4() {
const [render, setRender] = useState(items)
return (
<Box>
<List className="App">
<Repeat list={render}>
<RenderItem remove={remove} />
</Repeat>
</List>
<Button variant="contained" color="primary" onClick={add}>
Add
</Button>
</Box>
)
function add() {
setRender((items) => [
{ name: "Made up at " + Date.now(), on: false },
...items
])
}
function remove(item) {
setRender((items) => items.filter((i) => i !== item))
}
}
これは、リスト内の各項目に対してRenderItemが繰り返される必要があります.解決策
ので、書きましょう
Repeat
好きなことをするコンポーネント.最初に知っていることは、我々が書くとき
const something = <RenderItem remove={remove}/>
以下のようなオブジェクトを返します.{type: RenderItem, props: {remove: remove}}
. この情報を使用して、この項目を次のような追加の小道具でレンダリングできます.
const template = <RenderItem remove={remove}/>
return <template.type {...template.props} something="else"/>
繰り返しコンポーネントを作るために使いましょう.function Repeat({
list,
children,
item = children.type ? children : undefined,
}) {
if(!item) return
return list.map((iterated, index) => {
return (
<item.type
{...{ ...item.props, item: iterated, index }}
/>
)
})
}
我々は、レンダリングするもののためのアイテム支柱を使用して、繰り返しコンポーネントの子供たちにそれをデフォルトします.その後、このリストを実行します.リスト内の各項目についてindex
とitem
によって渡されるパラメータに基づいて.map()
これは良いですが、おそらく私たちが指定しない場合はchildren
or item
. 私たちは、単純なコンポーネントを作ることによってそれをすることができて、それよりむしろ後ろの背中としてそれを使うことができますundefined
.function Simple({ item }) {
return <div>{typeof item === "object" ? JSON.stringify(item) : item}</div>
}
この関数には問題があります.そのため、まず、WeakMap
リスト項目の一意キーを作成するには
const keys = new WeakMap()
let repeatId = 0
function getKey(item) {
if (typeof item === "object") {
const key = keys.get(item) ?? repeatId++
keys.set(item, key)
return key
} else {
return item
}
}
この関数は、それが遭遇した項目の各オブジェクトタイプの一意の数値キーを作成します.現在の項目からキーを抽出するためのキー機能を取るか、デフォルトとしてこの一般的なものを使用するために、我々は繰り返し機能を強化することができます:function Repeat({
list,
children,
item = children.type ? children : <Simple />,
keyFn = getKey
}) {
return list.map((iterated, index) => {
return (
<item.type
key={keyFn(iterated)}
{...{ ...item.props, item: iterated, index }}
/>
)
})
}
たぶん、最終的なステップは、「アイテム」から離れていくつかの他の支柱を内部の構成要素のために使われるのを許すことです.それはかなり簡単です.function Repeat({
list,
children,
item = children.type ? children : <Simple />,
pass = "item", // Take the name for the prop
keyFn = getKey
}) {
return list.map((iterated, index) => {
return (
<item.type
key={keyFn(iterated)}
// Use the passed in name
{...{ ...item.props, [pass]: iterated, index }}
/>
)
})
}
最後の結果は完全に機能し、多くのバージョンよりも理由を使用して簡単に.map()
- 少なくとも私の心に――)記事からのすべてのコードは、ここにあります.
-
追加
コメントで作られたポイントのカップルに答えて、私は私がちょうど最適化すると思いました
Repeat
より少ないメモリと割り当てを使用するには.map()
バージョン.私も削除.map()
リストが超ロングで、ガベージコレクションがかなり強力であるならば、アプリケーションロジックにより多くの変更が必要であるので、私はそれが必要でないと思います.function Repeat({
list,
children,
item = children.type ? children : <Simple />,
pass = "item",
keyFn = getKey
}) {
const [keys] = useState({})
const [output] = useState([])
let index = 0
for (let iterated of list) {
let key = keyFn(iterated) ?? index
output[index] = keys[key] = keys[key] || {
...item,
key,
props: { ...item.props, [pass]: iterated }
}
output[index].props.index = index
index++
}
output.length = index
return output
}
このバージョンについての1つの不満は、それがコンポーネントがマウントされている間、もはや見られないリスト項目のための構造を保持するということであるかもしれません.それらを取り除くことは可能かもしれませんが、overkillのようです、そして、あなたがallocationについて心配しているならば、それはトレードオフです.自然.map()
任意の場合、すべての場合は、配列やサブアイテムを作成している-今ので問題がある場合は、このバージョンはそれを避けるためのパターンです.Reference
この問題について(反応リストなし.マップ), 我々は、より多くの情報をここで見つけました https://dev.to/miketalbot/react-lists-without-map-25d5テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol