๐ŸฅขRedux์˜ ์„ ํƒ๊ธฐ

8372 ๋‹จ์–ด reactreduxjavascript

A โ€œselectorโ€ is simply a function that accepts Redux state as an argument and returns data that is derived from that state.

A selector is a small function you write that can take the entire Redux state, and pick out a value from it.


mapStateToProps๊ฐ€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์•„์‹ญ๋‹ˆ๊นŒ? ์ „์ฒด ์ƒํƒœ๋ฅผ ๊ฐ€์ ธ์™€์„œ ๊ฐ’์„ ์„ ํƒํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์„ ํƒ์ž๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ทธ๋ ‡๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋ณด๋„ˆ์Šค๋กœ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๊นŒ์ง€ ๊ฐ’์„ ์บ์‹ฑํ•˜์—ฌ ์„ฑ๋Šฅ๋„ ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค. ์Œ โ€“ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์„ ํƒ์ž๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?



Redux ์ €์žฅ์†Œ ์ƒํƒœ๋ฅผ ์ตœ์†Œํ™”ํ•˜๊ณ  ํ•„์š”์— ๋”ฐ๋ผ ์ƒํƒœ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ํŒŒ์ƒ์‹œํ‚ค๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ข‹์Šต๋‹ˆ๋‹ค. ์„ ํƒ์ž๋Š” ์ด๋ฅผ ๋„์™€์ค๋‹ˆ๋‹ค. ๊ทธ๋“ค์€ ํŒŒ์ƒ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ์–ด Redux๊ฐ€ ๊ฐ€๋Šฅํ•œ ์ตœ์†Œํ•œ์˜ ์ƒํƒœ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์„ ํƒ์ž๋„ ๋งค์šฐ ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค. ์„ ํƒ์ž๋Š” ์ธ์ˆ˜ ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” ํ•œ ๋‹ค์‹œ ๊ณ„์‚ฐ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์„ ํƒ๊ธฐ์˜ ๋ช‡ ๊ฐ€์ง€ ์˜ˆ:



๊ธฐ์ดˆ์ ์ธ :

selectUsers = state => state.users;


ID๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•ฝ๊ฐ„ ๋ณต์žกํ•จ:

selectUserIds = state => state.users.map(user => user.id);


๋” ๋ณต์žกํ•œ:

selectUserIdsOfName = (state, name) => state.users.filter(user => user.name === name);


์˜ˆ



Redux๋Š” ์ƒํƒœ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” ์ €์žฅ์†Œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋” ํฐ ์•ฑ์—์„œ ํ•ด๋‹น ์ƒํƒœ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๊ฐœ์ฒด์˜ ๊ฐ ํ‚ค๊ฐ€ ๋ณ„๋„์˜ ๊ฐ์†๊ธฐ์— ์˜ํ•ด ๊ด€๋ฆฌ๋˜๋Š” ๊ฐœ์ฒด์ž…๋‹ˆ๋‹ค.

{
  currentUser: {
    token,
    userId,
    username
  },
  shoppingCart: {
    itemIds,
    loading,
    error
  },
  products: {
    itemsById,
    loading,
    error
  }
}


์ฒซ์งธ, ์„ ํƒ์ž ์—†์ด


  • Redux ์ƒํƒœ์—์„œ React ๊ตฌ์„ฑ ์š”์†Œ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์•ผ ํ•  ๋•Œ ์ „์ฒด ์ƒํƒœ๋ฅผ ์ทจํ•˜๊ณ  ํ•„์š”ํ•œ ๋ถ€๋ถ„์„ ์„ ํƒํ•˜๋Š” mapStateToProps ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
  • ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ๋‹ด๊ธด ์ƒํ’ˆ์„ ๋ณด์—ฌ์ฃผ๊ณ  ์‹ถ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๊ธฐ ์œ„ํ•ด์„œ๋Š” ์•„์ดํ…œ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. Buuut shoppingCart์—๋Š” ํ•ญ๋ชฉ์ด ์—†์Šต๋‹ˆ๋‹ค. ํ•ญ๋ชฉ ID๋งŒ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ ID๋ฅผ ๊ฐ€์ ธ์™€์„œ products.items ๋ฐฐ์—ด์—์„œ ์ฐพ์•„๋ณด์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • function mapStateToProps(state) {
      return {
        items: state.shoppingCart.itemIds.map(id => 
          state.products.itemsById[id]
        )
      }
    }
    


    ์ƒํƒœ ๋ชจ์–‘์„ ๋ณ€๊ฒฝํ•˜๋ฉด mapStateToProps๊ฐ€ ์ค‘๋‹จ๋ฉ๋‹ˆ๋‹ค.



    ์ด์ œ โ€“ "์•Œ๋‹ค์‹œํ”ผ... shoppingCart๋Š” ๋…๋ฆฝ ์‹คํ–‰ํ˜•์ด ์•„๋‹Œ currentUser์˜ ์†์„ฑ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค."๋ผ๊ณ  ๊ฒฐ์ •ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ฉ๋‹ˆ๊นŒ? ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ƒํƒœ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์žฌ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

    currentUser: {
        token,
        userId,
        username,
        shoppingCart: {
          itemIds,
          loading,
          error
        },
      },
      products: {
        itemsById,
        loading,
        error
      }
    }
    


  • ๊ธ€์Ž„, ์ด์ œ ์ด์ „ mapStateToProps ๊ธฐ๋Šฅ์ด ์†์ƒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํ˜„์žฌ state.shoppingCart ์— ์žˆ๋Š” state.currentUser.shoppingCart ๋ฅผ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค.
  • ์•ฑ์— state.shoppingCart ๋ฅผ ์ฐธ์กฐํ•˜๋Š” ์—ฌ๋Ÿฌ ์œ„์น˜๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ๋ชจ๋“  ์œ„์น˜๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒƒ์€ ๊ณ ํ†ต์Šค๋Ÿฌ์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์„ฑ๊ฐ€์‹  ์—…๋ฐ์ดํŠธ ํ”„๋กœ์„ธ์Šค์— ๋Œ€ํ•œ ๋‘๋ ค์›€์ด๋‚˜ ํšŒํ”ผ๊ฐ€ ์ƒํƒœ๋ฅผ ์žฌ๊ตฌ์„ฑํ•ด์•ผ ํ•จ์„ ์•Œ๋ฉด์„œ๋„ ์ƒํƒœ๋ฅผ ์žฌ๊ตฌ์„ฑํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ƒํƒœ์˜ ๋ชจ์–‘์— ๋Œ€ํ•œ ์ง€์‹์„ ์ค‘์•™ ์ง‘์ค‘ํ™”ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค๋ฉดโ€ฆ ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ฐพ๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๊ณ  ์žˆ๋Š” ์ผ์ข…์˜ ํ•จ์ˆ˜๋ผ๊ณ  ๋ถ€๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    ๊ธ€์Ž„, ๊ทธ๊ฒƒ์ด ๋ฐ”๋กœ ์„ ํƒ๊ธฐ์˜ ์šฉ๋„์ž…๋‹ˆ๋‹ค :)

    ๋ฆฌํŒฉํ† ๋ง: ๊ฐ„๋‹จํ•œ ์„ ํƒ๊ธฐ ์ž‘์„ฑ



    ๊นจ์ง„mapStateToProps์„ ๋‹ค์‹œ ์ž‘์„ฑํ•˜๊ณ  ์ƒํƒœ ์•ก์„ธ์Šค๋ฅผ ์„ ํƒ๊ธฐ๋กœ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

    // put this in some global-ish place,
    // like selectors.js,
    // and import it when you need to access this bit of state
    function selectShoppingCartItems(state) {
      return state.currentUser.shoppingCart.itemIds.map(id => 
        state.products.itemsById[id]
      );
    }
    
    function mapStateToProps(state) {
      return {
        items: selectShoppingCartItems(state)
      }
    }
    


    ๋‹ค์Œ์— ์ƒํƒœ ๋ชจ์–‘์ด ๋ณ€๊ฒฝ๋˜๋ฉด ํ•˜๋‚˜์˜ ์„ ํƒ๊ธฐ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋ฉด ์™„๋ฃŒ๋ฉ๋‹ˆ๋‹ค.

    ๋ฉ”๋ชจ์ด์ œ์ด์…˜


  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์„ ํƒ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ์ œ๊ณตํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด ์ƒ์ ์˜ ์ƒํƒœ์— ๋Œ€ํ•ด ์ง‘์ค‘์ ์ธ ์ •๋ ฌ ์ž‘์—…์„ ์‹คํ–‰ํ•ด์•ผ ํ•˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. mapStateToProps() ํ•จ์ˆ˜์—์„œ ์„ ํƒ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ ์ „๋‹ฌ๋œ ์ž‘์—…์œผ๋กœ ์ธํ•ด ์ƒํƒœ๊ฐ€ ์—…๋ฐ์ดํŠธ๋  ๋•Œ๋งˆ๋‹ค ์ž‘์—…์ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
  • ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งŒ ๊ฐ’๋น„์‹ผ ์ •๋ ฌ ์ž‘์—…์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ๋ฉ”๋ชจ์ด์ œ์ด์…˜์˜ ๊ฐœ๋…์ด ๊ตฌ์ถœ๋ฉ๋‹ˆ๋‹ค.
  • ๋ฉ”๋ชจ์ด์ œ์ด์…˜์€ ์บ์‹ฑ์˜ ํ•œ ํ˜•ํƒœ์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ํ•จ์ˆ˜์— ๋Œ€ํ•œ ์ž…๋ ฅ์„ ์ถ”์ ํ•˜๊ณ  ๋‚˜์ค‘์— ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋„๋ก ์ž…๋ ฅ๊ณผ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•˜๋Š” ์ž‘์—…์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ์ด์ „๊ณผ ๋™์ผํ•œ ์ž…๋ ฅ์œผ๋กœ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ํ•จ์ˆ˜๋Š” ์‹ค์ œ ์ž‘์—…์„ ๊ฑด๋„ˆ๋›ธ ์ˆ˜ ์žˆ์œผ๋ฉฐ ํ•ด๋‹น ์ž…๋ ฅ ๊ฐ’์„ ๋งˆ์ง€๋ง‰์œผ๋กœ ์ˆ˜์‹ ํ–ˆ์„ ๋•Œ ์ƒ์„ฑํ•œ ๊ฒƒ๊ณผ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๊ฒฐ๋ก 



    ์„ ํƒ๊ธฐ๋Š” Redux ์ƒํƒœ๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›์•„๋“ค์ด๊ณ  ํ•ด๋‹น ์ƒํƒœ์—์„œ ํŒŒ์ƒ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ์„ ํƒ๊ธฐ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์ „์—ญ ์ƒํƒœ ํŠธ๋ฆฌ๋ฅผ ์บก์Šํ™”ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

    ์ข‹์€ ์›นํŽ˜์ด์ง€ ์ฆ๊ฒจ์ฐพ๊ธฐ