skip to Main Content

I’m a beginner with react and I have this code:

import {NavLink as Link} from 'react-router-dom'

return (
  <div>
    {posts.map((actualData, index) => (
      <Link to={'/' + actualData.id}>
        <div className='format_link'>
          <div className='image_link'>
            <div className='image'>
              <img
                className='images'
                id={actualData.id}
                src={getImage(actualData.path, 0)}
                alt='Italian Trulli'
              />
              <button
                className='arrow right'
                id={'button' + actualData.id}
                onClick={() => changeImageNext(actualData.id, actualData.path)}>
                {'>'}
              </button>
              <button
                className='arrow left'
                id={'button' + actualData.id}
                onClick={() => changeImagePre(actualData.id, actualData.path)}>
                {'<'}
              </button>
            </div>
          </div>
          <div className='desc_link'>
            <div className='event'>
              <div className='save'> </div>
            </div>
          </div>
        </div>
      </Link>
    ))}
  </div>
)

I would like to use the buttons but if I pressed them I would be sent to the article link. Furthermore, I tried to replace buttons with Button by→import { Button } from 'semantic-ui-react'Or to use event.stopPropagation()(although maybe I didn’t use it correctly), I used it like this:

function changeImagePre(e, id, images) {
  e.stopPropagation()
  var num = parseInt(result[id].images)
  //...
}

return (
  <div>
    {posts.map((actualData, index) => (
      <Link to={'/' + actualData.id}>
        <div className='format_link'>
          <div className='image_link'>
            <div className='image'>
              <img
                className='images'
                id={actualData.id}
                src={getImage(actualData.path, 0)}
                alt='Italian Trulli'
              />
              <button
                className='arrow right'
                id={'button' + actualData.id}
                onClick={(e) =>
                  changeImageNext(actualData.id, actualData.path)
                }>
                {'>'}
              </button>
              <button
                className='arrow left'
                id={'button' + actualData.id}
                onClick={(e) => changeImagePre(actualData.id, actualData.path)}>
                {'<'}
              </button>
            </div>
          </div>
          <div className='desc_link'>
            <div className='event'>
              <div className='save'> </div>
            </div>
          </div>
        </div>
      </Link>
    ))}
  </div>
)

Therefore, to use the buttons in the Link how could I do? 🙁

3

Answers


  1. Always prefer atomic design to avoid duplicating your code. First, write a separate component.

    export default function Btn(props) {
      return (
        <button
          type="button"
          onClick={() => window.open(`${props.link}`)}>
          {props.text}
        </button>
      )
    }
    

    Then, in your code, you merely need to import it and use it as follows:

    import Btn from '@/components/global/atoms/Btn'
    
    {/* Here goes the rest of your code */}
    
    <Btn
      link="https://www.mywebsite.com"
      text="Button Text"
    ></Btn>
    
    Login or Signup to reply.
  2. If you are already using react-router-dom. You can directly use history or navigate based on the version you are using. If you are using a version lesser than 6 then you can use

    export function App(props) {
      const history = useHistory();
      return (
        <div className='App'>
          <button 
          onClick={() => history.push("/moveToHere")}
          >Click Me</button>
        </div>
      );
    }
    

    But if you’re using react-router-dom@6^ then you can use navigate which comes with the package.

    export function App(props) {
      const history = useNavigate();
      return (
        <div className='App'>
          <button 
          onClick={() => navigate("/moveToHere")}
          >Click Me</button>
        </div>
      );
    }
    

    With these function calls you can also pass parameters between this navigation and those get stored in the location state which can be dereferenced by using useLocation hook.

    Login or Signup to reply.
  3. It is generally considered poor UI/UX to nest interactable elements within other interactable elements, but if you absolutely must nest the buttons inside the link and don’t want the buttons to trigger the link action then you should prevent the click event from propagating to the Link component.

    The issue with your code is that the button’s onClick event object isn’t forwarded to the callback.

    onClick={(e) => changeImageNext(actualData.id, actualData.path)}
    

    It should instead be

    onClick={(e) => changeImageNext(e, actualData.id, actualData.path)}
    
    function changeImagePre(e, id, images) {
      e.stopPropagation();
      ...
    }
    
    return (
      <div>
        {posts.map((actualData) => (
          <Link to={`/${actualData.id}`} key={actualData.id}>
            <div className='format_link'>
              <div className='image_link'>
                <div className='image'>
                  <img
                    className='images'
                    id={actualData.id}
                    src={getImage(actualData.path, 0)}
                    alt='Italian Trulli'
                  />
                  <button
                    className='arrow right'
                    id={'button' + actualData.id}
                    onClick={(e) => {
                      changeImageNext(e, actualData.id, actualData.path);
                    }}
                  >
                    {'>'}
                  </button>
                  <button
                    className='arrow left'
                    id={'button' + actualData.id}
                    onClick={(e) => {
                      changeImagePre(e, actualData.id, actualData.path);
                    }}
                  >
                    {'<'}
                  </button>
                </div>
              </div>
              <div className='desc_link'>
                <div className='event'>
                  <div className='save'></div>
                </div>
              </div>
            </div>
          </Link>
        ))}
      </div>
    )
    

    This is just a preference of mine, but I like to write curried onClick callback handlers as it makes for simpler code, though at the expense of readability if you are unfamiliar with currying. The idea is that the callback will be immediately called and passed the mapped arguments, and returns a function that accepts the onClick event object to be used as the onClick handler function.

    Example:

    function changeImagePre(id, images) {
      return (e) => {
        e.stopPropagation();
        ... // id and images closed over in callback scope
      };
    }
    
    return (
      <div>
        {posts.map((actualData) => (
          <Link to={`/${actualData.id}`} key={actualData.id}>
            <div className='format_link'>
              <div className='image_link'>
                <div className='image'>
                  <img
                    className='images'
                    id={actualData.id}
                    src={getImage(actualData.path, 0)}
                    alt='Italian Trulli'
                  />
                  <button
                    className='arrow right'
                    id={'button' + actualData.id}
                    onClick={changeImageNext(actualData.id, actualData.path)}
                  >
                    {'>'}
                  </button>
                  <button
                    className='arrow left'
                    id={'button' + actualData.id}
                    onClick={changeImagePre(actualData.id, actualData.path)}
                  >
                    {'<'}
                  </button>
                </div>
              </div>
              <div className='desc_link'>
                <div className='event'>
                  <div className='save'></div>
                </div>
              </div>
            </div>
          </Link>
        ))}
      </div>
    )
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search