Giter Site home page Giter Site logo

Comments (10)

TrySound avatar TrySound commented on May 13, 2024 1

@srcspider New context api is not singleton. Data you pass is kept in the tree. You may add many sibling providers and every consumer will consume data of only own provider.

const Cx = createContext(0);

const Component = () => (
  <>
    <Cx.Consumer>
      {value => value /* 0 */}
    </Cx.Consumer>

    <Cx.Provider value={1}>
      <Cx.Consumer>
        {value => value /* 1 */}
      </Cx.Consumer>
    </Cx.Provider>

    <Cx.Provider value={2}>
      <Cx.Consumer>
        {value => value /* 2 */}
      </Cx.Consumer>
    </Cx.Provider>
  </>
)

from rfcs.

bvaughn avatar bvaughn commented on May 13, 2024 1

Every time your Chaos component is rendered, it will produce different outputs. This is not how React components are supposed to work.

That being said, here's how you could create the same "game" you've shown using the new context API: https://codesandbox.io/s/24y59mj0jn

The solution you provided, to my understanding has the same limitations as if I were to just have a random nodejs module exporting ThingA and every other module importing said module (you just did it with a lot more code). I would achieve the same result and suffer from the same limitation, that being that it is inherently a singleton context. I never want singleton contexts. Even if it is a single ThingA in the application, having it as a singleton means, "there can never be anything ThingA on the page."

No, although I guess I can see how you came to that conclusion. Maybe this example helps clarify?

import {ComponentX, ThingAProvider} from 'some-component-x-library';

<>
  <ThingAProvider value="foo">
    <ComponentX /> <!-- gets "foo" as "thing a" -->
    <ThingAProvider value="bar">
      <ComponentX /> <!-- gets "bar" as "thing a" -->
    </ThingAProvider/>
  </ThingAProvider>

  <ThingAProvider value="baz">
    <ComponentX /> <!-- gets "baz" as "thing a" -->
  </ThingAProvider>

  <ComponentX /> <!-- gets null as "thing a" -->
</>

The context API supports overriding values via nested providers.

from rfcs.

trueadm avatar trueadm commented on May 13, 2024

What's this comment in relation to? I don't think you meant to make an issue here? (Same as the other issue you made)

from rfcs.

amrdraz avatar amrdraz commented on May 13, 2024

@srcspider are you referring to context?

from rfcs.

srcspider avatar srcspider commented on May 13, 2024

@amrdraz yes, see discussion in #23

from rfcs.

bvaughn avatar bvaughn commented on May 13, 2024

I'm a little unclear on what you're asking here too. Terms like "component x" and "thing a" are a little too ambiguous. But I think you're asking how you could write a library with a component that consumes a context value that must be provided by users of your library. In that case, you could do something like this:

Your Component X library

const ThingAContext = React.createContext(null);

// Export the provider for libraries using Component X.
// These libraries are required to supply their own context value.
export const ThingAProvider = ThingAContext.Provider;

// Export Component X for use however it is intended.
export const ComponentX = props => (
  <ThingAContext.Consumer>
    {thingA => {
      if (thingA === null) {
        throw Error('You must provide a value for Thing A');
      }

      return (
        <SomeInternalComponentThatRequiresThingA
          {...props}
          thingA={thingA}
        />
      );
    }}
  </ThingAContext.Consumer>
);

Code that uses your library

import {ComponentX, ThingAProvider} from 'some-component-x-library';

// I need to specify my own value
<ThingAProvider value="My own value for thing A">
  <div>
    <div>
      <ComponentX foo={123} bar="abc" />
    </div>
  </div>
</ThingAProvider>

from rfcs.

srcspider avatar srcspider commented on May 13, 2024

@bvaughn

This is clearly getting us nowhere fast. I've given an answer to your post at the end, but the short of it is that it's not what I meant.

To make this "problem" as simple as possible I've boiled it down to a "fizzbuzz"-like problem instead. This way it's very simple and we just have to talk code. Solve the problem within the given limitations and any confusion goes away.

Template

https://jsfiddle.net/54s6p6ux/

class Player extends React.Component {
    render() {
        let chosenColor = undefined;
        return (
            <div>Player chose color {chosenColor}</div>
        );
    }
}

// This simulates there being a boundry betweent the Player component
// and the game component. If there was none the obviously there is no
// need for a "context" system of any sorts at all!
function Chaos(/* no arguments allowed! */) {
    let comp = <Player/>;
    let randomTimes = Math.floor((Math.random() * 10) + 1);
    while ( --randomTimes > 0) {
        comp = <div>{comp}</div>
    }
    return comp;
}

class Game extends React.Component {
    render() {
        return (
            <React.Fragment>
                <h2>{this.props.name}</h2>
                <p><b>Game Colors</b>: {this.props.colors.join(', ')}</p>
                <Chaos/><Chaos/><Chaos/>
            </React.Fragment>
        );
  }
}

for (let i = 1; i <= 100; ++i) {
    let colors = [];
        for (let j = 0; j < 10; ++j) {
        colors.push(`c${i}-${j}`);
    }

    let container = document.createElement('div')
    document.body.appendChild(container);

    ReactDOM.render(
        <Game name={`Game ${i}`} colors={colors} />,
        container
    );
}

Limitations

  • you may not change the Chaos function at all!
  • only the Chaos function is allowed to work with Player (simulates realworld deep hierarchies)
  • the colors must pass though (no cheating using time based race conditions or other methods)

Objective

100 games are created on the page. Each game has 9 unique colors (names not important). Each game has 3 players. Each player randomly chooses one of the 9 colors.

A template with all the boring stuff is provided. You just have to fill in the code so that colors make it to the players and they print one at random.

Example

Here is the solution using the classic context system.

https://jsfiddle.net/8xqwfma1/


With regard to your example, just so it doesn't go unanswered:

The solution you provided, to my understanding has the same limitations as if I were to just have a random nodejs module exporting ThingA and every other module importing said module (you just did it with a lot more code). I would achieve the same result and suffer from the same limitation, that being that it is inherently a singleton context. I never want singleton contexts. Even if it is a single ThingA in the application, having it as a singleton means, "there can never be anything ThingA on the page."

from rfcs.

srcspider avatar srcspider commented on May 13, 2024

@bvaughn

That being said, here's how you could create the same "game" you've shown using the new context API: https://codesandbox.io/s/24y59mj0jn

The solution is wrong because you manipulated the Chaos function (see Limitations section in initial post). Chaos represents parts of the code you don't manipulate (such as 3rd-party intermediate components that sit between your root "Game" component and your "Player" component, in this case).

Based on what TrySound posted, the "solution" is this https://codesandbox.io/s/98jrv09qvw

@TrySound

@srcspider New context api is not singleton. Data you pass is kept in the tree. You may add many sibling providers and every consumer will consume data of only own provider.

Well I'm happy to be proven wrong. And you're right I was thiking that due to how simplistic it looks (all blog posts about it so far don't touch on it either I think).

But at the same time I don't feel too good by how complicated it seems to actually be internally. The fact it can't be used in the constructor or any function outside of render is a big led down still. I'm to assume that the reason it's not able to pass it directly to the constructor or some componentDidRecievedContext is not just some style choice? and has something to do with limitations behind the logic of workLoop, beginWork and updateContextConsumer in React's internals?

Seems I'm doomed to have to create 3 separate components each time I need to create one.

But again thanks for clearing up it's not a singleton pattern.

from rfcs.

srcspider avatar srcspider commented on May 13, 2024

Closing based on clarification from @gaearon in #23

from rfcs.

bvaughn avatar bvaughn commented on May 13, 2024

The solution is wrong because you manipulated the Chaos function (see Limitations section in initial post).

Right. I arbitrarily placed the Context.Consumer component within the Chaos component because (in the isolated example) it seemed to make sense. You can move the consumer into Player if you prefer, or anywhere between the Context.Provider and Player.

Updated example at:
https://codesandbox.io/s/j2ny0xnw23

The fact it can't be used in the constructor or any function outside of render is a big led down still.

For anyone else who sees this thread in the future, this comment on issue #23 explains how you can access context values in the constructor (or elsewhere outside of render). You just need to lift the consumer up a level.

For example, "lifting up" can be done with a higher order function, like so:

function withColorsContext(Component) {
  return function ColorsContextConsumer(props) {
    return (
      <ColorsContext.Consumer>
        {colors => <Component {...props} colors={colors} />}
      </ColorsContext.Consumer>
    );
  };
}

from rfcs.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.