Search code examples
reactjsreact-reduxsemantic-ui

Display selected value from dropdown using semantic ui React


I'm really new on React, Redux. I am trying to display the selected value from dropdown, uses semantic ui. I updated at state but can not show the value on the screen, and the dropdown not close (after added closeOnChange- not recognize this attribute, why?}

** Component.js**

const ProductDetails = () => {
    const {productId} = useParams()
    
    const selectedProd = useSelector((state) => state.allProducts.products.find(product => 
        product.id === parseInt(productId)
        ));
    const products = useSelector((state) => state.allProducts.products)       
    let {rank} = selectedProd    
    const dispatch = useDispatch()  
    const handleDropDownSelect = (event) => {
        //update rank
        selectedProd.rank = parseInt(event.dataset.value)       
        //update allProducts
        dispatch(updateProducts(products,selectedProd))        
    }
return(
<div className="ui left floated simple selection dropdown"   value={rank} onClick={e=>handleDropDownSelect(e.target)}>
                                <i className="dropdown icon"></i>
                                <div className="default value" value={rank}></div>
                                <div className="left floated menu" >
                                <div className="item" data-value="1" data-key="1">1</div>
                                <div className="item" data-value="2" data-key="2">2</div>
                                <div className="item" data-value="3" data-key="3">3</div>
                                <div className="item" data-value="4" data-key="4">4</div>
                                <div className="item" data-value="5" data-key="5">5</div>
                                </div>
                            </div>)

redux/reducers/actions.js

export const updateProducts = (products,product) => {
    const indexOfItem = products.findIndex(q => q.id === product.id);
    if (indexOfItem > -1) {
        products[indexOfItem] = product;
     }
    return {
        type: ActionTypes.SET_PRODUCTS,
        payload: products
    };
};

redux/constans/types.js

export const ActionTypes = {
    SET_PRODUCTS: "SET_PRODUCTS",   
}

redux/reducers/index.js

import { combineReducers } from 'redux'
import { productReducer} from './productReducer'

const reducers = combineReducers({
    allProducts: productReducer,    
})

export default reducers

What I'm missing?


Solution

  • This is most likely you do NOT change the reference of state.allProducts.products, so React doesn't re-render the UI

    You should map products as the Redux Todos Example

    And add a online demo such as CodeSandBox would help us give you better suggestions

    OK, according to the demo at codesandbox.io/s/products-forked-kmbwz, here we have at leaset two problems:

    1. the Route ProductDetails didn't rerender after the dropdown select chance because of you didn't change the reference of selectedProd.

    View on this link I forked from yours, see file /src/Components/ProductDetails.js on Line 14-15, I add a console.log to debug the Component whether will be rerendered. And Line 31-33, I change the reference of new selectedProd by destructuring assignment. The when you click the dropdown option, the UI will be rerender, because you see the log.

    1. The dropdown component is buggy:
    • You bind a value to div. But div doesn't have a value prop, you should explicitly display it as I do at Line 54.
    • click the value part of dropdown will trigger handleDropDownSelect event, so you will see NaN sometimes

    I really suggest you follow the official Redux Todos Example before you start. And the problem you face here is that, React naturally render the UI when data(props/state) change, so the reference of data is change or not is important to React. And as you play React longer, immutable data structure such as Immerjs will help a lot. And again, the Redux or React docs are much more detailed than I explained, read them🤪